From 6111bd7c47d26bf5c31dafdead3de22e082765ef Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Tue, 16 Sep 2025 18:28:49 +0200 Subject: [PATCH 01/28] feurst --- demos/tutorial/set_operator.cpp | 2 +- include/samurai/algorithm.hpp | 25 +- include/samurai/level_cell_array.hpp | 45 +- include/samurai/subset/apply.hpp | 114 +-- include/samurai/subset/box_view.hpp | 84 +++ include/samurai/subset/concepts.hpp | 44 -- include/samurai/subset/contraction.hpp | 115 +++ .../samurai/subset/fixed_capacity_array.hpp | 94 +++ include/samurai/subset/lca_view.hpp | 103 +++ include/samurai/subset/nary_set_operator.hpp | 198 +++++ include/samurai/subset/node.hpp | 690 +----------------- include/samurai/subset/projection.hpp | 145 ++++ include/samurai/subset/set_base.hpp | 130 ++++ include/samurai/subset/start_end_fct.hpp | 275 ------- include/samurai/subset/translation.hpp | 82 +++ .../subset/traversers/box_traverser.hpp | 64 ++ .../traversers/contraction_traverser.hpp | 68 ++ .../traversers/difference_id_traverser.hpp | 67 ++ .../traversers/difference_traverser.hpp | 131 ++++ .../traversers/intersection_traverser.hpp | 105 +++ .../subset/traversers/lca_batch_traverser.hpp | 80 ++ .../subset/traversers/lca_traverser.hpp | 64 ++ .../traversers/projection_traverser.hpp | 175 +++++ .../subset/traversers/set_traverser_base.hpp | 55 ++ .../traversers/translation_traverser.hpp | 61 ++ .../subset/traversers/union_traverser.hpp | 106 +++ include/samurai/subset/utils.hpp | 109 +-- include/samurai/subset/visitor.hpp | 379 ---------- tests/test_subset.cpp | 6 +- 29 files changed, 2069 insertions(+), 1547 deletions(-) create mode 100644 include/samurai/subset/box_view.hpp delete mode 100644 include/samurai/subset/concepts.hpp create mode 100644 include/samurai/subset/contraction.hpp create mode 100644 include/samurai/subset/fixed_capacity_array.hpp create mode 100644 include/samurai/subset/lca_view.hpp create mode 100644 include/samurai/subset/nary_set_operator.hpp create mode 100644 include/samurai/subset/projection.hpp create mode 100644 include/samurai/subset/set_base.hpp delete mode 100644 include/samurai/subset/start_end_fct.hpp create mode 100644 include/samurai/subset/translation.hpp create mode 100644 include/samurai/subset/traversers/box_traverser.hpp create mode 100644 include/samurai/subset/traversers/contraction_traverser.hpp create mode 100644 include/samurai/subset/traversers/difference_id_traverser.hpp create mode 100644 include/samurai/subset/traversers/difference_traverser.hpp create mode 100644 include/samurai/subset/traversers/intersection_traverser.hpp create mode 100644 include/samurai/subset/traversers/lca_batch_traverser.hpp create mode 100644 include/samurai/subset/traversers/lca_traverser.hpp create mode 100644 include/samurai/subset/traversers/projection_traverser.hpp create mode 100644 include/samurai/subset/traversers/set_traverser_base.hpp create mode 100644 include/samurai/subset/traversers/translation_traverser.hpp create mode 100644 include/samurai/subset/traversers/union_traverser.hpp delete mode 100644 include/samurai/subset/visitor.hpp diff --git a/demos/tutorial/set_operator.cpp b/demos/tutorial/set_operator.cpp index 4f46700b1..82a4bd53e 100644 --- a/demos/tutorial/set_operator.cpp +++ b/demos/tutorial/set_operator.cpp @@ -98,7 +98,7 @@ int main() u[cell] = cell.indices[0]; }); - auto subset1 = samurai::intersection(ca[0], samurai::contraction(ca[1], 1)); + auto subset1 = samurai::intersection(ca[0], samurai::contract(ca[1], 1)); subset1.on(0)( [&](const auto& i, auto) { diff --git a/include/samurai/algorithm.hpp b/include/samurai/algorithm.hpp index bd6c21617..2d43ce269 100644 --- a/include/samurai/algorithm.hpp +++ b/include/samurai/algorithm.hpp @@ -14,6 +14,9 @@ #include "cell.hpp" #include "mesh_holder.hpp" +#include "concepts.hpp" +#include "subset/node.hpp" + using namespace xt::placeholders; namespace samurai @@ -111,18 +114,28 @@ namespace samurai } } - template + template inline void for_each_interval(const Mesh& mesh, Func&& f) { using mesh_id_t = typename Mesh::config::mesh_id_t; for_each_interval(mesh[mesh_id_t::cells], std::forward(f)); } - template - class Subset; - - template - inline void for_each_interval(Subset& set, Func&& f) + //~ template + //~ class Subset; + + //~ template + //~ inline void for_each_interval(Subset& set, Func&& f) + //~ { + //~ set( + //~ [&](const auto& i, const auto& index) + //~ { + //~ f(set.level(), i, index); + //~ }); + //~ } + + template + inline void for_each_interval(const SetBase& set, Func&& f) { set( [&](const auto& i, const auto& index) diff --git a/include/samurai/level_cell_array.hpp b/include/samurai/level_cell_array.hpp index 48b79c717..515d0d65d 100644 --- a/include/samurai/level_cell_array.hpp +++ b/include/samurai/level_cell_array.hpp @@ -94,8 +94,11 @@ namespace samurai LevelCellArray() = default; LevelCellArray(const LevelCellList& lcl); - template - LevelCellArray(Subset set); + //~ template + //~ LevelCellArray(Subset set); + + template + LevelCellArray(const SetBase& set); LevelCellArray(std::size_t level, const Box& box); LevelCellArray(std::size_t level, @@ -344,17 +347,41 @@ namespace samurai } } - template - template - inline LevelCellArray::LevelCellArray(Subset set) - : m_level(set.level()) - { - set( + //~ template + //~ template + //~ inline LevelCellArray::LevelCellArray(Subset set) + //~ : m_level(set.level()) + //~ { + //~ set( + //~ [this](const auto& i, const auto& index) + //~ { + //~ add_interval_back(i, index); + //~ }); + //~ } + + template + template + inline LevelCellArray::LevelCellArray(const SetBase& set) + : m_level(set.level()) + { + set( [this](const auto& i, const auto& index) { add_interval_back(i, index); }); - } + } + + //~ template + //~ template + //~ inline LevelCellArray::LevelCellArray(Subset set) + //~ : m_level(set.level()) + //~ { + //~ set( + //~ [this](const auto& i, const auto& index) + //~ { + //~ add_interval_back(i, index); + //~ }); + //~ } template inline LevelCellArray::LevelCellArray(std::size_t level, const Box& box) diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index b8652afe2..0d234a185 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -3,119 +3,45 @@ #pragma once -#include "concepts.hpp" -#include "utils.hpp" +#include "set_base.hpp" namespace samurai { namespace detail { - template - bool apply_impl(Set&& global_set, Func&& func, Container& index) + template + void apply_rec(const Set& set, Func&& func, Index& index, std::integral_constant d_ic) { - auto set = global_set.template get_local_set(global_set.level(), index); - auto start_and_stop = global_set.template get_start_and_stop_function(); + using traverser_t = typename Set::template traverser_t; + using current_interval_t = typename traverser_t::current_interval_t; - if constexpr (dim != 1) + for (traverser_t traverser = set.get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) { - auto func_int = [&](const auto& interval) + current_interval_t interval = traverser.current_interval(); + if constexpr (d == 0) { - for (auto i = interval.start; i < interval.end; ++i) + func(interval, index); + } + else + { + for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) { - index[dim - 2] = i; - if (apply_impl(std::forward(global_set), std::forward(func), index)) - { - return true; - } + apply_rec(set, std::forward(func), index, std::integral_constant{}); } - return false; - }; - return apply(set, start_and_stop, func_int); - } - else - { - auto func_int = [&](const auto& interval) - { - return func(interval, index); - }; - return apply(set, start_and_stop, func_int); + } } } } - template - void apply(Set&& global_set, Func&& user_func) + template + void apply(const Set& set, Func&& func) { - constexpr std::size_t dim = std::decay_t::dim; - xt::xtensor_fixed> index; - - auto func = [&](const auto& interval, const auto& yz) - { - user_func(interval, yz); - return false; - }; + constexpr std::size_t dim = SetTraits::getDim(); - if (global_set.exist()) - { - detail::apply_impl(std::forward(global_set), func, index); - } - } - - template - bool empty_check(Set&& global_set) - { - constexpr std::size_t dim = std::decay_t::dim; xt::xtensor_fixed> index; - - auto func = [](const auto&, const auto&) - { - return true; - }; - - if (global_set.exist()) + if (set.exist()) { - return !detail::apply_impl(std::forward(global_set), func, index); - } - return true; - } - - template - requires IsSetOp || IsIntervalListVisitor - bool apply(Set&& set, StartEnd&& start_and_stop, Func&& func) - { - using interval_t = typename std::decay_t::interval_t; - using value_t = typename interval_t::value_t; - - interval_t result; - int r_ipos = 0; - set.next(0, std::forward(start_and_stop)); - auto scan = set.min(); - - while (scan < sentinel && !set.is_empty()) - { - bool is_in = set.is_in(scan); - - if (is_in && r_ipos == 0) - { - result.start = scan; - r_ipos = 1; - } - else if (!is_in && r_ipos == 1) - { - result.end = scan; - r_ipos = 0; - - auto true_result = set.shift() >= 0 ? result >> static_cast(set.shift()) - : result << -static_cast(set.shift()); - if (func(true_result)) - { - return true; - } - } - - set.next(scan, std::forward(start_and_stop)); - scan = set.min(); + detail::apply_rec(set, std::forward(func), index, std::integral_constant{}); } - return false; } } diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp new file mode 100644 index 000000000..3a988534b --- /dev/null +++ b/include/samurai/subset/box_view.hpp @@ -0,0 +1,84 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_base.hpp" +#include "traversers/box_traverser.hpp" + +namespace samurai +{ + template + class BoxView; + + template + struct SetTraits> + { + template + using traverser_t = BoxTraverser; + + static constexpr std::size_t getDim() + { + return B::dim; + } + }; + + template + class BoxView : public SetBase> + { + using Self = BoxView; + using Base = SetBase; + + public: + + template + using traverser_t = typename Base::template traverser_t; + + BoxView(const std::size_t level_impl, const B& box) + : m_level_impl(level_impl) + , m_box(box) + { + } + + std::size_t level_impl() const + { + return m_level_impl; + } + + bool exist_impl() const + { + return m_box.is_valid(); + } + + bool empty_impl() const + { + return !exist_impl(); + } + + template + traverser_t get_traverser_impl([[maybe_unused]] const index_t& index, std::integral_constant) const + { + if constexpr (d != Base::dim - 1) + { + assert(m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]); + } + + return traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]); + } + + private: + + std::size_t m_level_impl; + const B& m_box; + }; + + template + struct SelfTraits { using Type = BoxView; }; + + template + BoxView self(const B& box) + { + return BoxView(box); + } + +} diff --git a/include/samurai/subset/concepts.hpp b/include/samurai/subset/concepts.hpp deleted file mode 100644 index 4fcdc6125..000000000 --- a/include/samurai/subset/concepts.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include - -namespace samurai -{ - template - class LevelCellArray; - // } - - // namespace samurai::experimental - // { - template - class SetTraverser; - - template - class IntervalListVisitor; - - template - struct is_setop : std::false_type - { - }; - - template - struct is_setop> : std::true_type - { - }; - - template - constexpr bool is_setop_v{is_setop>::value}; - - template - concept IsSetOp = is_setop_v; - - template - concept IsIntervalListVisitor = std::is_base_of_v::container_t>, std::decay_t>; - - template - concept IsLCA = std::same_as, T>; -} diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp new file mode 100644 index 000000000..e4f7fdef0 --- /dev/null +++ b/include/samurai/subset/contraction.hpp @@ -0,0 +1,115 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_base.hpp" +#include "traversers/contraction_traverser.hpp" + +namespace samurai +{ + + template + class Contraction; + + template + struct SetTraits> + { + template + using traverser_t = ContractionTraverser>; + + static constexpr std::size_t getDim() + { + return SetTraits::getDim(); + } + }; + + template + class Contraction : public SetBase> + { + using Self = Contraction; + using Base = SetBase; + + public: + + template + using traverser_t = typename Base::template traverser_t; + + using value_t = typename Base::value_t; + using contraction_t = std::array; + using do_contraction_t = std::array; + + Contraction(const Set& set, const contraction_t& contraction) + : m_set(set) + , m_contraction(contraction) + { + assert(std::all_of(m_contraction.cbegin(), + m_contraction.cend(), + [](const contraction_t& c) + { + return c >= 0; + })); + } + + Contraction(const Set& set, const value_t contraction) + : m_set(set) + { + assert(contraction >= 0); + std::fill(m_contraction.begin(), m_contraction.end(), contraction); + } + + Contraction(const Set& set, const value_t contraction, const do_contraction_t& do_contraction) + : m_set(set) + { + for (std::size_t i=0; i!=m_contraction.size(); ++i) + { + m_contraction[i] = contraction*do_contraction[i]; + } + + } + + std::size_t level_impl() const + { + return m_set.level_impl(); + } + + bool exist_impl() const + { + return m_set.exist_impl(); + } + + bool empty_impl() const + { + return m_set.empty_impl(); + } + + template + traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + { + return traverser_t(m_set.get_traverser_impl(index, d_ic), m_contraction[d]); + } + + private: + + Set m_set; + contraction_t m_contraction; + }; + + template + auto contract(const Set& set, const typename Contraction::Type>::contraction_t& contraction) + { + return Contraction(self(set), contraction); + } + + template + auto contract(const Set& set, const typename Contraction::Type>::value_t contraction) + { + return Contraction(self(set), contraction); + } + + template + auto contract(const Set& set, const typename Contraction::Type>::value_t contraction, const typename Contraction::Type>::do_contraction_t& do_contraction) + { + return Contraction(self(set), contraction, do_contraction); + } +} diff --git a/include/samurai/subset/fixed_capacity_array.hpp b/include/samurai/subset/fixed_capacity_array.hpp new file mode 100644 index 000000000..299fa11a1 --- /dev/null +++ b/include/samurai/subset/fixed_capacity_array.hpp @@ -0,0 +1,94 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +template +class FixedCapacityNonTrivialStorage +{ + static_assert(not std::is_trivially_constructible::value); +public: + constexpr T* data() { return reinterpret_cast< T*>(m_core.data()); } + constexpr const T* data() const { return reinterpret_cast(m_core.data()); } +private: + std::array m_core; +}; + +#include +#include + +template +class FixedCapacityArray +{ + using Storage = std::conditional_t< std::is_trivially_constructible::value, std::array, FixedCapacityNonTrivialStorage >; +public: + FixedCapacityArray() : m_end(m_storage.data()) {} + + FixedCapacityArray(const std::size_t size, const T& value = T()) requires(std::is_trivially_constructible::value) + { + assert(size <= N); + m_end = begin() + size; + std::fill(begin(), end(), value); + } + + template + FixedCapacityArray(const FixedCapacityArray& other) requires(N2 <= N) + : m_end(m_storage.data() + other.size()) + { + if constexpr (std::is_fundamental::value) + { + std::copy(std::cbegin(other), std::cend(other), begin()); + } + else + { + const T* srcIt = std::cbegin(other); + for (T* dstIt = begin(); dstIt != end(); ++dstIt, ++srcIt) + { + std::construct_at(dstIt, *srcIt); + } + } + } + + ~FixedCapacityArray() { clear(); } + + T* begin() { return m_storage.data(); } + T* end() { return m_end; } + + const T* begin() const { return m_storage.data(); } + const T* end() const { return m_end; } + + const T& operator[](const std::size_t i) const { return *(begin() + i); } + T& operator[](const std::size_t i) { return *(begin() + i); } + + std::size_t size() const { return end() - begin(); } + + constexpr std::size_t capacity() const { return N; } + + template + void emplace_back(Args&&... args) + { + assert(size() < N); + std::construct_at(m_end, std::forward(args)...); + ++m_end; + } + + void push_back(const T& value) { emplace_back(value); } + + void pop_back() + { + if (begin() != m_end) + { + --m_end; + std::destroy_at(m_end); + } + } + + void clear() + { + std::destroy(begin(), end()); + m_end = begin(); + } +private: + Storage m_storage; + T* m_end; +}; diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp new file mode 100644 index 000000000..566659e46 --- /dev/null +++ b/include/samurai/subset/lca_view.hpp @@ -0,0 +1,103 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_base.hpp" +#include "traversers/lca_traverser.hpp" + +namespace samurai +{ + template + class LCAView; + + template + struct SetTraits> + { + template + using traverser_t = LCATraverser; + + static constexpr std::size_t getDim() + { + return LCA::dim; + } + }; + + template + class LCAView : public SetBase> + { + using Self = LCAView; + using Base = SetBase; + + public: + + template + using traverser_t = typename Base::template traverser_t; + + explicit LCAView(const LCA& lca) + : m_lca(lca) + { + } + + std::size_t level_impl() const + { + return m_lca.level(); + } + + bool exist_impl() const + { + return !empty_impl(); + } + + bool empty_impl() const + { + return m_lca.empty(); + } + + template + traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const + { + if constexpr (d != Base::dim - 1) + { + const auto& y = index[d]; + const auto& y_intervals = m_lca[d + 1]; + const auto& y_offsets = m_lca.offsets(d + 1); + // we need to find an interval that contains y. + const auto y_interval_it = std::find_if(y_intervals.cbegin(), + y_intervals.cend(), + [y](const auto& y_interval) + { + return y_interval.contains(y); + }); + if (y_interval_it != y_intervals.cend()) + { + const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); + return traverser_t(m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]), + m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1])); + } + else + { + return traverser_t(m_lca[d].cend(), m_lca[d].cend()); + } + } + else + { + return traverser_t(m_lca[d].cbegin(), m_lca[d].cend()); + } + } + + private: + + const LCA& m_lca; + }; + + template + struct SelfTraits { using Type = LCAView; }; + + template + LCAView self(const LCA& lca) + { + return LCAView(lca); + } + +} diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp new file mode 100644 index 000000000..8fbef7a26 --- /dev/null +++ b/include/samurai/subset/nary_set_operator.hpp @@ -0,0 +1,198 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "traversers/difference_id_traverser.hpp" +#include "traversers/difference_traverser.hpp" +#include "traversers/intersection_traverser.hpp" +#include "traversers/union_traverser.hpp" + +#include "set_base.hpp" + +namespace samurai +{ + enum class SetOperator + { + UNION, + INTERSECTION, + DIFFERENCE + }; + + template + class NArySetOperator; + + template + struct SetTraits> + { + using Childrens = std::tuple; + + template + using traverser_t = UnionTraverser...>; + + static constexpr std::size_t getDim() + { + return SetTraits>::getDim(); + } + }; + + template + struct SetTraits> + { + using Childrens = std::tuple; + + template + using traverser_t = IntersectionTraverser::template traverser_t...>; + + static constexpr std::size_t getDim() + { + return SetTraits>::getDim(); + } + }; + + template + struct SetTraits> + { + using Childrens = std::tuple; + + template + using traverser_t = std::conditional_t...>, + DifferenceIdTraverser...>>; + + static constexpr std::size_t getDim() + { + return SetTraits>::getDim(); + } + }; + + template + class NArySetOperator : public SetBase> + { + using Self = NArySetOperator; + using Base = SetBase; + using Childrens = typename SetTraits::Childrens; + + public: + + template + using traverser_t = typename Base::template traverser_t; + + static constexpr std::size_t nIntervals = std::tuple_size_v; + + explicit NArySetOperator(const Sets&... sets) + : m_sets(sets...) + { + m_level_impl = std::apply( + [](const auto&... set) -> std::size_t + { + return vmax(set.level_impl()...); + }, + m_sets); + + enumerate_const_items(m_sets, + [this](const auto i, const auto& set) + { + m_shifts[i] = std::size_t(m_level_impl - set.level_impl()); + }); + } + + std::size_t level_impl() const + { + return m_level_impl; + } + + bool exist_impl() const + { + return std::apply( + [](const auto first_set, const auto&... other_sets) -> std::size_t + { + if constexpr (op == SetOperator::UNION) + { + return first_set.exist_impl() || (other_sets.exist_impl() || ...); + } + else if constexpr (op == SetOperator::INTERSECTION) + { + return first_set.exist_impl() && (other_sets.exist_impl() && ...); + } + else + { + return first_set.exist_impl(); + } + }, + m_sets); + } + + bool empty_impl() const + { + return std::apply( + [this](const auto first_set, const auto&... other_sets) -> std::size_t + { + if constexpr (op == SetOperator::UNION) + { + return first_set.empty_impl() && (other_sets.empty_impl() && ...); + } + else if constexpr (op == SetOperator::INTERSECTION) + { + return first_set.empty_impl() || (other_sets.empty_impl() || ...); + } + else + { + return first_set.empty_impl(); + } + }, + m_sets); + } + + template + traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + { + return get_traverser_impl_impl(index, d_ic, std::make_index_sequence{}); + } + + private: + + template + traverser_t get_traverser_impl_impl(const index_t& index, std::integral_constant d_ic, std::index_sequence) const + { + return traverser_t(m_shifts, std::get(m_sets).get_traverser_impl(index >> m_shifts[Is], d_ic)...); + } + + Childrens m_sets; + std::size_t m_level_impl; + std::array m_shifts; + }; + + //////////////////////////////////////////////////////////////////////// + //// functions + //////////////////////////////////////////////////////////////////////// + + template + auto union_(const Sets&... sets) + requires(sizeof...(Sets) >= 1) + { + //~ using Union = NArySetOperator...>; + using Union = NArySetOperator::Type...>; + + return Union(self(sets)...); + } + + template + auto intersection(const Sets&... sets) + requires(sizeof...(Sets) >= 2) + { + using Intersection = NArySetOperator::Type...>; + + return Intersection(self(sets)...); + } + + template + auto difference(const Sets&... sets) + requires(sizeof...(Sets) >= 2) + { + using Difference = NArySetOperator::Type...>; + + return Difference(self(sets)...); + } + +} // namespace samurai diff --git a/include/samurai/subset/node.hpp b/include/samurai/subset/node.hpp index 6114bf0f4..cc1a00278 100644 --- a/include/samurai/subset/node.hpp +++ b/include/samurai/subset/node.hpp @@ -3,687 +3,11 @@ #pragma once -#include -#include -#include -#include -#include -#include - -#include - -#include "../algorithm.hpp" #include "apply.hpp" -#include "concepts.hpp" -#include "samurai/list_of_intervals.hpp" -#include "start_end_fct.hpp" -#include "visitor.hpp" - -namespace samurai -{ - - template - void apply(Set&& global_set, Func&& func); - - template - class Subset - { - public: - - static constexpr std::size_t dim = get_set_dim_v; - using set_type = std::tuple; - using interval_t = get_interval_t; - - Subset(Op&& op, StartEndOp&& start_end_op, S&&... s) - : m_operator(std::forward(op)) - , m_start_end_op(std::forward(start_end_op)) - , m_s(std::forward(s)...) - , m_ref_level(compute_max(s.ref_level()...)) - , m_level(compute_max(s.level()...)) - , m_min_level(m_level) - { - std::apply( - [this](auto&&... args) - { - (args.ref_level(m_ref_level), ...); - }, - m_s); - } - - auto& on(auto level) - { - auto ilevel = static_cast(level); - if (ilevel > m_ref_level) - { - ref_level(ilevel); - } - m_min_level = std::min(m_min_level, ilevel); - m_level = ilevel; - return *this; - } - - template - void operator()(Func&& func) - { - apply(*this, std::forward(func)); - } - - template - void apply_op(ApplyOp&&... op) - { - auto func = [&](auto& interval, auto& index) - { - (op(m_level, interval, index), ...); - }; - apply(*this, func); - } - - inline void to_stream(std::ostream& os) - { - apply_op( - [&](const auto level, const auto& i, const auto& index) - { - os << "level: " << level << ", i: " << i << ", index: " << index << std::endl; - }); - } - - template - auto get_local_set(auto level, auto& index, Func_goback_beg&& goback_fct_beg, Func_goback_end&& goback_fct_end) - { - int shift = static_cast(this->ref_level()) - static_cast(this->level()); - m_start_end_op(m_level, m_min_level, m_ref_level); - - return std::apply( - [this, &index, shift, level, &goback_fct_beg, &goback_fct_end](auto&&... args) - { - return SetTraverser(shift, - get_operator(m_operator), - args.template get_local_set( - level, - index, - m_start_end_op.template goback(std::forward(goback_fct_beg)), - m_start_end_op.template goback(std::forward(goback_fct_end)))...); - }, - m_s); - } - - template - auto get_local_set(auto level, auto& index) - { - return get_local_set(level, index, default_function_(), default_function_()); - } - - template - auto get_start_and_stop_function(Func_start&& start_fct, Func_end&& end_fct) - { - m_start_end_op(m_level, m_min_level, m_ref_level); - - return std::apply( - [this, &start_fct, &end_fct](auto&& arg, auto&&... args) - { - if constexpr (std::is_same_v) - { - return std::make_tuple(std::move(arg.template get_start_and_stop_function( - m_start_end_op.template start(std::forward(start_fct)), - m_start_end_op.template end(std::forward(end_fct)))), - std::move(args.template get_start_and_stop_function( - m_start_end_op.template start(std::forward(start_fct)), - m_start_end_op.template end(std::forward(end_fct))))...); - } - else - { - return std::make_tuple(std::move(arg.template get_start_and_stop_function( - m_start_end_op.template start(std::forward(start_fct)), - m_start_end_op.template end(std::forward(end_fct)))), - std::move(args.template get_start_and_stop_function( - m_start_end_op.template start(std::forward(start_fct)), - m_start_end_op.template end(std::forward(end_fct))))...); - } - }, - m_s); - } - - template - auto get_start_and_stop_function() - { - return get_start_and_stop_function(default_function(), default_function()); - } - - auto level() const - { - return m_level; - } - - auto ref_level() const - { - return m_ref_level; - } - - void ref_level(auto level) - { - m_ref_level = level; - std::apply( - [this](auto&&... args) - { - (args.ref_level(m_ref_level), ...); - }, - m_s); - } - - bool empty() - { - return empty_check(*this); - } - - bool exist() const - { - return std::apply( - [this](auto&&... args) - { - return m_operator.exist(args...); - }, - m_s); - } - - protected: - - Op m_operator; - StartEndOp m_start_end_op; - set_type m_s; - std::size_t m_ref_level; - std::size_t m_level; - std::size_t m_min_level; - }; - - template - requires IsLCA - struct Self - { - static constexpr std::size_t dim = lca_t::dim; - using interval_t = typename lca_t::interval_t; - using value_t = typename interval_t::value_t; - - explicit Self(const lca_t& lca) - : m_lca(lca) - , m_level(lca.level()) - , m_ref_level(m_level) - , m_min_level(m_level) - { - } - - template - void operator()(Func&& func) - { - apply(*this, std::forward(func)); - } - - template - void apply_op(ApplyOp&&... op) - { - auto func = [&](auto& interval, auto& index) - { - (op(m_level, interval, index), ...); - }; - apply(*this, func); - } - - template - auto get_local_set(auto level, auto& index, Func_goback_beg&& goback_fct_beg, Func_goback_end&& goback_fct_end) - { - if (m_lca[d - 1].empty()) - { - return IntervalListVisitor(IntervalListRange(m_lca[d - 1], 0, 0)); - } - - if constexpr (dim == d) - { - m_offsets[d - 1].clear(); - m_offsets[d - 1].push_back({0, m_lca[d - 1].size()}); - - return IntervalListVisitor(m_lca.level(), - m_level, - m_ref_level, - IntervalListRange(m_lca[d - 1], 0, static_cast(m_lca[d - 1].size()))); - } - else - { - if (m_offsets[d].empty() || m_lca[d].empty()) - { - return IntervalListVisitor(IntervalListRange(m_lca[d - 1], 0, 0)); - } - - auto new_goback_fct_beg = m_func.template goback(std::forward(goback_fct_beg)); - - if (level <= m_level && level >= m_lca.level()) - { - m_offsets[d - 1].clear(); - - auto current_index = start_shift(new_goback_fct_beg(level, index[d - 1]).second, - static_cast(m_lca.level()) - static_cast(m_level)); - auto j = find_on_dim(m_lca, d, m_offsets[d][0][0], m_offsets[d][0][1], current_index); - - if (j == std::numeric_limits::max()) - { - return IntervalListVisitor(IntervalListRange(m_lca[d - 1], 0, 0)); - } - - auto io = static_cast(m_lca[d][j].index + current_index); - auto& offsets = m_lca.offsets(d); - m_offsets[d - 1].push_back({offsets[io], offsets[io + 1]}); - - return IntervalListVisitor(m_lca.level(), - m_level, - m_ref_level, - IntervalListRange(m_lca[d - 1], - static_cast(offsets[io]), - static_cast(offsets[io + 1]))); - } - else - { - auto new_goback_fct_end = m_func.template goback(std::forward(goback_fct_end)); - - auto min_index = start_shift(new_goback_fct_beg(level, index[d - 1]).second, - static_cast(m_lca.level()) - static_cast(m_level)); - - auto max_index = end_shift(new_goback_fct_end(level, index[d - 1] + 1).second, - static_cast(m_lca.level()) - static_cast(m_level)); - - m_work[d - 1].clear(); - m_offsets[d - 1].clear(); - - if constexpr (d == dim - 1) - { - auto j_min = lower_bound_interval(m_lca[d].begin() + static_cast(m_offsets[d][0][0]), - m_lca[d].begin() + static_cast(m_offsets[d][0][1]), - min_index); - auto j_max = upper_bound_interval(j_min, m_lca[d].begin() + static_cast(m_offsets[d][0][1]), max_index) - - 1; - - if (j_min != m_lca[d].end() && j_min <= j_max) - { - auto start_offset = static_cast(j_min->index + j_min->start); - if (j_min->contains(min_index)) - { - start_offset = static_cast(j_min->index + min_index); - } - - auto end_offset = static_cast(j_max->index + j_max->end); - if (j_max->contains(max_index)) - { - end_offset = static_cast(j_max->index + max_index); - } - - if (start_offset == end_offset) - { - return IntervalListVisitor(IntervalListRange(m_lca[d - 1], 0, 0)); - } - - m_offsets[d - 1].push_back({start_offset, end_offset}); - - ListOfIntervals list_of_intervals; - for (std::size_t o = m_lca.offsets(d)[start_offset]; o < m_lca.offsets(d)[end_offset]; ++o) - { - auto start = m_lca[d - 1][o].start; - auto end = m_lca[d - 1][o].end; - list_of_intervals.add_interval({start, end}); - } - - for (auto& i : list_of_intervals) - { - m_work[d - 1].push_back(i); - } - } - } - else - { - ListOfIntervals list_of_intervals; - - for (auto& offset : m_offsets[d]) - { - for (std::size_t io = offset[0]; io < offset[1]; ++io) - { - auto j_min = lower_bound_interval( - m_lca[d].begin() + static_cast(m_lca.offsets(d + 1)[io]), - m_lca[d].begin() + static_cast(m_lca.offsets(d + 1)[io + 1]), - min_index); - auto j_max = upper_bound_interval( - j_min, - m_lca[d].begin() + static_cast(m_lca.offsets(d + 1)[io + 1]), - max_index) - - 1; - - if (j_min != m_lca[d].begin() + static_cast(m_lca.offsets(d + 1)[io + 1]) && j_min <= j_max) - { - auto start_offset = static_cast(j_min->index + j_min->start); - if (j_min->contains(min_index)) - { - start_offset = static_cast(j_min->index + min_index); - } - - auto end_offset = static_cast(j_max->index + j_max->end); - if (j_max->contains(max_index)) - { - end_offset = static_cast(j_max->index + max_index); - } - - if (start_offset == end_offset) - { - continue; - } - - m_offsets[d - 1].push_back({start_offset, end_offset}); - - for (std::size_t o = m_lca.offsets(d)[start_offset]; o < m_lca.offsets(d)[end_offset]; ++o) - { - auto start = m_lca[d - 1][o].start; - auto end = m_lca[d - 1][o].end; - list_of_intervals.add_interval({start, end}); - } - } - } - - for (auto& i : list_of_intervals) - { - m_work[d - 1].push_back(i); - } - } - } - if (m_work[d - 1].empty()) - { - return IntervalListVisitor(IntervalListRange(m_lca[d - 1], 0, 0)); - } - return IntervalListVisitor(m_lca.level(), m_level, m_ref_level, IntervalListRange(m_lca[d - 1], m_work[d - 1])); - } - } - } - - template - auto get_local_set(auto level, auto& index) - - { - return get_local_set(level, index, default_function_(), default_function_()); - } - - template - auto get_start_and_stop_function(Func_start&& start_fct, Func_end&& end_fct) - { - m_func(m_level, m_min_level, m_ref_level); - auto new_start_fct = m_func.template start(std::forward(start_fct)); - auto new_end_fct = m_func.template end(std::forward(end_fct)); - return std::make_tuple(std::move(new_start_fct), std::move(new_end_fct)); - } - - template - auto get_start_and_stop_function() - - { - return get_start_and_stop_function(default_function(), default_function()); - } - - auto ref_level() const - { - return m_ref_level; - } - - void ref_level(auto level) - { - m_ref_level = level; - } - - auto level() const - { - return m_level; - } - - auto& on(auto level) - { - m_ref_level = std::max(m_ref_level, static_cast(level)); - m_min_level = std::min(m_min_level, static_cast(level)); - m_level = static_cast(level); - return *this; - } - - bool exist() const - { - return !m_lca.empty(); - } - - bool empty() const - { - return !m_lca.empty(); - } - - const lca_t& m_lca; - std::size_t m_level; - std::size_t m_ref_level; - std::size_t m_min_level; - start_end_function m_func; - std::array, dim - 1> m_work; - std::array>, dim> m_offsets; - }; - - namespace detail - { - template - auto transform(const LevelCellArray& lca) - { - return Self>(lca); - } - - template - auto transform(LevelCellArray& lca) - { - return Self>(lca); - } - - template - auto transform(E&& e) - { - return std::forward(e); - } - } - - template - inline std::ostream& operator<<(std::ostream& out, Subset& subset) - { - subset.to_stream(out); - return out; - } - - template - auto intersection(sets_t&&... sets) - { - static constexpr std::size_t dim = get_set_dim_v; - return std::apply( - [](auto&&... args) - { - return Subset(IntersectionOp(), start_end_function(), std::forward(args)...); - }, - std::make_tuple(detail::transform(std::forward(sets))...)); - } - - template - auto union_(sets_t&&... sets) - { - static constexpr std::size_t dim = get_set_dim_v; - return std::apply( - [](auto&&... args) - { - return Subset(UnionOp(), start_end_function(), std::forward(args)...); - }, - std::make_tuple(detail::transform(std::forward(sets))...)); - } - - template - auto difference(sets_t&&... sets) - { - static constexpr std::size_t dim = get_set_dim_v; - return std::apply( - [](auto&&... args) - { - return Subset(DifferenceOp(), start_end_function(), std::forward(args)...); - }, - std::make_tuple(detail::transform(std::forward(sets))...)); - } - - template - auto translate(set_t&& set, const stencil_t& stencil) - { - constexpr std::size_t dim = std::decay_t::dim; - return Subset(SelfOp(), - start_end_translate_function(xt::xtensor_fixed>(stencil)), - detail::transform(std::forward(set))); - } - - template - auto contraction(set_t&& set, int c) - { - constexpr std::size_t dim = std::decay_t::dim; - return Subset(SelfOp(), start_end_contraction_function(c), detail::transform(std::forward(set))); - } - - template - auto self(lca_t&& lca) - { - return Self>(std::forward(lca)); - } - - //----------------------------------------------------------------// - // Contract // - //----------------------------------------------------------------// - - template - auto contract_rec(const SubsetOrLCA& set, int width, const std::array& contract_directions) - { - static constexpr std::size_t dim = SubsetOrLCA::dim; - if constexpr (direction_index < dim) - { - using direction_t = xt::xtensor_fixed>; - - auto contracted_in_other_dirs = contract_rec(set, width, contract_directions); - direction_t dir; - dir.fill(0); - dir[direction_index] = contract_directions[direction_index] ? width : 0; - - return intersection(contracted_in_other_dirs, translate(set, dir), translate(set, -dir)); - } - else - { - if constexpr (IsLCA) - { - return self(set); - } - else - { - return set; - } - } - } - - /** - * @brief Contract a set in the specified directions. - * - * @tparam SubsetOrLCA The type of the set to contract. - * @param set The set or LevelCellArray to contract. - * @param width The contraction width. - * @param contract_directions An array indicating which directions to contract (true for contraction, false for no contraction). - * @return A new set that is contracted in the specified directions. - */ - template - auto contract(const SubsetOrLCA& set, std::size_t width, const std::array& contract_directions) - { - return contract_rec<0>(set, static_cast(width), contract_directions); - } - - /** - * @brief Contract a set in all directions. - * - * This function is a convenience wrapper that contracts the set in all dimensions. - * - * @tparam SubsetOrLCA The type of the set to contract. - * @param set The set or LevelCellArray to contract. - * @param width The contraction width. - * @return A new set that is contracted in all directions. - */ - template - auto contract(const SubsetOrLCA& set, std::size_t width) - { - std::array contract_directions; - std::fill(contract_directions.begin(), contract_directions.end(), true); - return contract(set, width, contract_directions); - } - - //--------------------------------------------------------------// - // Expand // - //--------------------------------------------------------------// - - template - auto expand_rec(const SubsetOrLCA& set, const std::array& expand_directions) - { - static constexpr std::size_t dim = SubsetOrLCA::dim; - using direction_t = xt::xtensor_fixed>; - - if constexpr (width == 0 && direction_index == dim) - { - if constexpr (IsLCA) - { - return self(set); - } - else - { - return set; - } - } - else if constexpr (width > 0) - { - auto expanded_layer = expand_rec(set, expand_directions); - direction_t dir; - dir.fill(0); - dir[direction_index] = expand_directions[direction_index] ? width : 0; - - return union_(expanded_layer, translate(set, dir), translate(set, -dir)); - } - else if constexpr (direction_index < dim) - { - auto expanded_in_other_dirs = expand_rec(set, expand_directions); - direction_t dir; - dir.fill(0); - dir[direction_index] = expand_directions[direction_index] ? width : 0; - - return union_(expanded_in_other_dirs, translate(set, dir), translate(set, -dir)); - } - } - - /** - * @brief Expand a set in the specified directions. - * - * @tparam SubsetOrLCA The type of the set to expand. - * @param set The set or LevelCellArray to expand. - * @param width The expansion width. - * @param expand_directions An array indicating which directions to expand (true for expansion, false for no expansion). - * @return A new set that is expanded in the specified directions. - */ - template - auto expand(const SubsetOrLCA& set, const std::array& expand_directions) - { - return expand_rec<0, width>(set, expand_directions); - } - - /** - * @brief Expand a set in all Cartesian directions (no diagonals!). - * - * This function is a convenience wrapper that expands the set in all dimensions. - * - * @tparam SubsetOrLCA The type of the set to expand. - * @param set The set or LevelCellArray to expand. - * @param width The expansion width. - * @return A new set that is expanded in all directions. - */ - template - auto expand(const SubsetOrLCA& set) - { - std::array expand_directions; - std::fill(expand_directions.begin(), expand_directions.end(), true); - return expand(set, expand_directions); - } -} +#include "box_view.hpp" +#include "lca_view.hpp" +#include "contraction.hpp" +#include "set_base.hpp" +#include "nary_set_operator.hpp" +#include "translation.hpp" +#include "utils.hpp" diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp new file mode 100644 index 000000000..18215f6fd --- /dev/null +++ b/include/samurai/subset/projection.hpp @@ -0,0 +1,145 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include + +#include +#include + +#include "traversers/projection_traverser.hpp" + +namespace samurai +{ + template + class Projection; + + template + struct SetTraits> + { + template + using traverser_t = ProjectionTraverser>; + + static constexpr std::size_t getDim() + { + return SetTraits::getDim(); + } + }; + + namespace detail + { + template struct Work; + + template + struct Work< Set, std::index_sequence > + { + template + using WorkElement = std::vector< typename Set::template traverser_t >; + + using Type = std::tuple< WorkElement... >; + }; + } + + template + using Work = typename detail::Work< Set, std::make_index_sequence::getDim()> >::Type; + + /* + * The main issue with projection, Coarsening specifically, is that + * the interval is extended upon projection e.g. both + * Proj([1,4),1,0) and Proj([0,3),1,0) results in [0, 2) + * It means the coarsening operation, unlike the translation e.g., + * is a unary, NON BIJECTIVE operation. + * Thus in more than 1d, if I'm projecting over more than 1 level_impl: + * Proj([5, 17), [18, 20), 2, 0) = [1, 3) + * So given a y_proj in [1, 3), we need to traverse accross multiple + * y. + * y_proj = 1 => y \in [4, 8) + * y_proj = 2 => y \in [8, 12) + * + */ + template + class Projection : public SetBase> + { + using Self = Projection; + using Base = SetBase; + + public: + + template + using traverser_t = typename Base::template traverser_t; + + using value_t = typename Base::value_t; + + Projection(const Set& set, const std::size_t level_impl) + : m_set(set) + , m_level_impl(level_impl) + { + if (m_level_impl < m_set.level_impl()) + { + m_projectionType = ProjectionType::COARSEN; + m_shift = m_set.level_impl() - m_level_impl; + } + else + { + m_projectionType = ProjectionType::REFINE; + m_shift = m_level_impl - m_set.level_impl(); + } + } + + std::size_t level_impl() const + { + return m_level_impl; + } + + bool exist_impl() const + { + return m_set.exist_impl(); + } + + bool empty_impl() const + { + return m_set.empty_impl(); + } + + template + traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const + { + if (m_projectionType == ProjectionType::COARSEN) + { + if constexpr (d != Base::dim - 1) + { + const value_t ymin = _index[d] << m_shift; + const value_t ymax = (_index[d] + 1) << m_shift; + + xt::xtensor_fixed> index(_index << m_shift); + + //~ std::vector::template traverser_t> set_traversers; + //~ set_traversers.reserve(size_t(ymax - ymin)); + FixedCapacityArray::template traverser_t, default_config::max_level> set_traversers; + + for (index[d] = ymin; index[d] != ymax; ++index[d]) + { + set_traversers.push_back(m_set.get_traverser_impl(index, d_ic)); + } + return traverser_t(set_traversers, m_shift); + } + else + { + return traverser_t(m_set.get_traverser_impl(_index << m_shift, d_ic), m_projectionType, m_shift); + } + } + else + { + return traverser_t(m_set.get_traverser_impl(_index >> m_shift, d_ic), m_projectionType, m_shift); + } + } + + private: + + Set m_set; + std::size_t m_level_impl; + ProjectionType m_projectionType; + std::size_t m_shift; + }; +} diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp new file mode 100644 index 000000000..af8f29af4 --- /dev/null +++ b/include/samurai/subset/set_base.hpp @@ -0,0 +1,130 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include + +#include + +#include "traversers/set_traverser_base.hpp" + +namespace samurai +{ + //////////////////////////////////////////////////////////////////////// + //// Forward Declarations + //////////////////////////////////////////////////////////////////////// + + template + struct SelfTraits; + + template + struct SetTraits; + + template + class SetBase; + + template + concept Set_concept = std::is_base_of, T>::value; + + template + class Projection; + + template + void apply(const Set& set, Func&& func); + + //////////////////////////////////////////////////////////////////////// + //// Class definition + //////////////////////////////////////////////////////////////////////// + + template + class SetBase + { + using DerivedTraits = SetTraits; + + public: + + template + using traverser_t = typename DerivedTraits::template traverser_t; + using interval_t = typename SetTraverserTraits>::interval_t; + using value_t = typename interval_t::value_t; + + static constexpr std::size_t dim = DerivedTraits::getDim(); + + const Derived& derived_cast() const + { + return static_cast(*this); + } + + Derived& derived_cast() + { + return static_cast(*this); + } + + std::size_t level() const + { + return derived_cast().level_impl(); + } + + bool exist() const + { + return derived_cast().exist_impl(); + } + + bool empty() const + { + return derived_cast().empty_impl(); + } + + template + traverser_t get_traverser(const index_t& index, std::integral_constant d_ic) const + { + return derived_cast().get_traverser_impl(index, d_ic); + } + + inline Projection on(const std::size_t level); + + template + void operator()(Func&& func) const + { + apply(derived_cast(), std::forward(func)); + } + + template + void apply_op(ApplyOp&&... op) const + { + const std::size_t l = level(); + + auto func = [l, &op...](auto& interval, auto& index) + { + (op(l, interval, index), ...); + }; + apply(derived_cast(), func); + } + }; + + template + struct SelfTraits { using Type = Set; }; + + template + const Set& self(const Set& set) + { + return set; + } + + + +} // namespace samurai + +#include "projection.hpp" + +namespace samurai +{ + + template + Projection SetBase::on(const std::size_t level) + { + return Projection(derived_cast(), level); + } + +} diff --git a/include/samurai/subset/start_end_fct.hpp b/include/samurai/subset/start_end_fct.hpp deleted file mode 100644 index 6c304ee28..000000000 --- a/include/samurai/subset/start_end_fct.hpp +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include "utils.hpp" - -namespace samurai -{ - - inline auto default_function() - { - return [](auto, auto i, auto) - { - return i; - }; - } - - inline auto default_function_() - { - return [](auto level, auto i) - { - return std::make_pair(level, i); - }; - } - - template - struct start_end_function - { - auto& operator()(std::size_t level, std::size_t min_level, std::size_t max_level) - { - m_level = level; - m_min_level = min_level; - m_shift = static_cast(max_level) - static_cast(min_level); - return *this; - } - - template - inline auto start(const Func& f) const - { - auto new_f = [&, f](auto level, auto i, auto dec) - { - if constexpr (from_diff_op) - { - dec = (static_cast(level) > m_level) ? 1 : 0; - } - int value = (((i - dec) >> m_shift) << m_shift) + dec; - return f(m_level, value, dec); - }; - return new_f; - } - - template - inline auto end(const Func& f) const - { - auto new_f = [&, f](auto level, auto i, auto dec) - { - if constexpr (from_diff_op) - { - dec = (static_cast(level) > m_level) ? 0 : 1; - } - int value = (((i - dec) >> m_shift) + dec) << m_shift; - return f(m_level, value, dec); - }; - return new_f; - } - - template - inline auto goback(const Func& f) const - { - auto new_f = [&, f](auto level, auto i) - { - auto [prev_lev, v] = f(level, i); - - int min_shift = static_cast(m_min_level) - static_cast(prev_lev); - int max_shift = static_cast(m_level) - static_cast(m_min_level); - - if constexpr (end) - { - i = end_shift(end_shift(v, min_shift), max_shift); - } - else - { - i = start_shift(start_shift(v, min_shift), max_shift); - } - - return std::make_pair(m_level, i); - }; - return new_f; - } - - std::size_t m_level; - int m_shift; - std::size_t m_min_level; - }; - - template - struct start_end_translate_function - { - using container_t = xt::xtensor_fixed>; - - explicit start_end_translate_function(const container_t& t) - : m_level(0) - , m_min_level(0) - , m_max_level(0) - , m_t(t) - { - } - - auto& operator()(auto level, auto min_level, auto max_level) - { - m_level = level; - m_min_level = min_level; - m_max_level = max_level; - return *this; - } - - template - inline auto start(const Func& f) const - { - auto new_f = [&, f](auto level, auto i, auto dec) - { - int max2curr = static_cast(m_max_level) - static_cast(level); - int curr2min = static_cast(level) - static_cast(m_min_level); - int min2max = static_cast(m_max_level) - static_cast(m_min_level); - - if constexpr (from_diff_op) - { - dec = (static_cast(level) > m_level) ? 1 : 0; - } - int value = (((((i - dec) >> max2curr) + m_t[d - 1]) >> curr2min) + dec) << min2max; - - return f(m_level, value, dec); - }; - return new_f; - } - - template - inline auto end(const Func& f) const - { - auto new_f = [&, f](auto level, auto i, auto dec) - { - int max2curr = static_cast(m_max_level) - static_cast(level); - int curr2min = static_cast(level) - static_cast(m_min_level); - int min2max = static_cast(m_max_level) - static_cast(m_min_level); - - if constexpr (from_diff_op) - { - dec = (static_cast(level) > m_level) ? 0 : 1; - } - int value = (((((i - dec) >> max2curr) + m_t[d - 1]) >> curr2min) + dec) << min2max; - - return f(m_level, value, dec); - }; - return new_f; - } - - template - inline auto goback(const Func& f) const - { - auto new_f = [&, f](auto level, auto i) - { - auto [prev_lev, v] = f(level, i); - - auto min_shift = static_cast(m_min_level) - static_cast(prev_lev); - auto max_shift = static_cast(m_level) - static_cast(m_min_level); - - if constexpr (end) - { - i = end_shift(end_shift(v, min_shift), max_shift) - m_t[d - 1]; - } - else - { - i = start_shift(start_shift(v, min_shift), max_shift) - m_t[d - 1]; - } - - return std::make_pair(m_level, i); - }; - return new_f; - } - - std::size_t m_level; - std::size_t m_min_level; - std::size_t m_max_level; - xt::xtensor_fixed> m_t; - }; - - template - struct start_end_contraction_function - { - explicit start_end_contraction_function(int c) - : m_level(0) - , m_min_level(0) - , m_max_level(0) - , m_c(c) - { - } - - auto& operator()(auto level, auto min_level, auto max_level) - { - m_level = level; - m_min_level = min_level; - m_max_level = max_level; - return *this; - } - - template - inline auto start(const Func& f) const - { - auto new_f = [&, f](auto level, auto i, auto dec) - { - int max2curr = static_cast(m_max_level) - static_cast(level); - int curr2min = static_cast(level) - static_cast(m_min_level); - int min2max = static_cast(m_max_level) - static_cast(m_min_level); - - if constexpr (from_diff_op) - { - dec = (static_cast(level) > m_level) ? 1 : 0; - dec = 1; - } - int value = (((((i - dec) >> max2curr) + m_c) >> curr2min) + dec) << min2max; - return f(m_level, value, dec); - }; - return new_f; - } - - template - inline auto end(const Func& f) const - { - auto new_f = [&, f](auto level, auto i, auto dec) - { - int max2curr = static_cast(m_max_level) - static_cast(level); - int curr2min = static_cast(level) - static_cast(m_min_level); - int min2max = static_cast(m_max_level) - static_cast(m_min_level); - - if constexpr (from_diff_op) - { - dec = (static_cast(level) > m_level) ? 0 : 1; - } - int value = (((((i - dec) >> max2curr) - m_c) >> curr2min) + dec) << min2max; - return f(m_level, value, dec); - }; - return new_f; - } - - template - inline auto goback(const Func& f) const - { - auto new_f = [&, f](auto level, auto i) - { - auto [prev_lev, v] = f(level, i); - - auto min_shift = static_cast(m_min_level) - static_cast(prev_lev); - auto max_shift = static_cast(m_level) - static_cast(m_min_level); - - if constexpr (end) - { - i = end_shift(end_shift(v, min_shift), max_shift) + m_c; - } - else - { - i = start_shift(start_shift(v, min_shift), max_shift) + m_c; - } - - return std::make_pair(m_level, i); - }; - return new_f; - } - - std::size_t m_level; - std::size_t m_min_level; - std::size_t m_max_level; - int m_c; - }; -} diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp new file mode 100644 index 000000000..2c9f496b9 --- /dev/null +++ b/include/samurai/subset/translation.hpp @@ -0,0 +1,82 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_base.hpp" +#include "traversers/translation_traverser.hpp" + +namespace samurai +{ + + template + class Translation; + + template + struct SetTraits> + { + template + using traverser_t = TranslationTraverser>; + + static constexpr std::size_t getDim() + { + return SetTraits::getDim(); + } + }; + + template + class Translation : public SetBase> + { + using Self = Translation; + using Base = SetBase; + using SelfTraits = SetTraits; + + public: + + template + using traverser_t = typename Base::template traverser_t; + + using value_t = typename Base::value_t; + using translation_t = xt::xtensor_fixed>; + + template + Translation(const Set& set, const translation_expr_t& translation_expr) + : m_set(set) + , m_translation(translation_expr) + { + } + + std::size_t level_impl() const + { + return m_set.level_impl(); + } + + bool exist_impl() const + { + return m_set.exist_impl(); + } + + bool empty_impl() const + { + return m_set.empty_impl(); + } + + template + traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + { + return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic), m_translation[d]); + } + + private: + + Set m_set; + translation_t m_translation; + }; + + template + auto translate(const Set& set, const translation_t& translation) + { + return Translation(self(set), translation); + } + +} diff --git a/include/samurai/subset/traversers/box_traverser.hpp b/include/samurai/subset/traversers/box_traverser.hpp new file mode 100644 index 000000000..fc4fe8b10 --- /dev/null +++ b/include/samurai/subset/traversers/box_traverser.hpp @@ -0,0 +1,64 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#include "../../box.hpp" +#include "../../interval.hpp" +#include "set_traverser_base.hpp" + +#pragma once + +namespace samurai +{ + template + concept Box_concept = std::same_as, T>; + + template + class BoxTraverser; + + template + struct SetTraverserTraits> + { + using interval_t = Interval; + using current_interval_t = const interval_t&; + }; + + template + class BoxTraverser : public SetTraverserBase> + { + using Self = BoxTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + + BoxTraverser(const value_t& start, const value_t& end) + : m_current_interval{start, end} + , m_empty(false) + { + } + + inline bool is_empty() const + { + return m_empty; + } + + inline void next_interval() + { + assert(!is_empty()); + m_empty = true; + } + + inline current_interval_t current_interval() const + { + return m_current_interval; + } + + private: + + interval_t m_current_interval; + bool m_empty; + }; +} diff --git a/include/samurai/subset/traversers/contraction_traverser.hpp b/include/samurai/subset/traversers/contraction_traverser.hpp new file mode 100644 index 000000000..577443462 --- /dev/null +++ b/include/samurai/subset/traversers/contraction_traverser.hpp @@ -0,0 +1,68 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../utils.hpp" +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class ContractionTraverser; + + template + struct SetTraverserTraits> + { + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = interval_t; + }; + + template + class ContractionTraverser : public SetTraverserBase> + { + using Self = ContractionTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + + ContractionTraverser(const SetTraverser& set_traverser, const value_t contraction) + : m_set_traverser(set_traverser) + , m_contraction(contraction) + { + assert(m_contraction >= 0); + } + + inline bool is_empty() const + { + return m_set_traverser.is_empty(); + } + + inline void next_interval() + { + assert(!is_empty()); + m_set_traverser.next_interval(); + while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) + { + m_set_traverser.next_interval(); + } + } + + inline current_interval_t current_interval() const + { + return current_interval_t(m_set_traverser.current_interval().start + m_contraction, + m_set_traverser.current_interval().end - m_contraction); + } + + private: + + SetTraverser m_set_traverser; + value_t m_contraction; + }; + +} diff --git a/include/samurai/subset/traversers/difference_id_traverser.hpp b/include/samurai/subset/traversers/difference_id_traverser.hpp new file mode 100644 index 000000000..f074393b5 --- /dev/null +++ b/include/samurai/subset/traversers/difference_id_traverser.hpp @@ -0,0 +1,67 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../../static_algorithm.hpp" +#include "../utils.hpp" +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class DifferenceIdTraverser; + + template + struct SetTraverserTraits> + { + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = interval_t; + }; + + template + class DifferenceIdTraverser : public SetTraverserBase> + { + using Self = DifferenceIdTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + + static constexpr std::size_t nIntervals = 1 + sizeof...(OtherSetTraversers); + + DifferenceIdTraverser(const std::array& shifts, + const FirstSetTraverser& set_traverser, + const OtherSetTraversers&...) + : m_set_traverser(set_traverser) + , m_shift(shifts[0]) + { + } + + inline bool is_empty() const + { + return m_set_traverser.is_empty(); + } + + inline void next_interval() + { + assert(!is_empty()); + m_set_traverser.next_interval(); + } + + inline current_interval_t current_interval() const + { + return current_interval_t{m_set_traverser.current_interval().start << m_shift, m_set_traverser.current_interval().end << m_shift}; + } + + private: + + FirstSetTraverser m_set_traverser; + std::size_t m_shift; + }; + +} diff --git a/include/samurai/subset/traversers/difference_traverser.hpp b/include/samurai/subset/traversers/difference_traverser.hpp new file mode 100644 index 000000000..5d3da595e --- /dev/null +++ b/include/samurai/subset/traversers/difference_traverser.hpp @@ -0,0 +1,131 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../../static_algorithm.hpp" +#include "../utils.hpp" +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class DifferenceTraverser; + + template + struct SetTraverserTraits> + { + using Childrens = std::tuple; + using interval_t = typename SetTraverserTraits>::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class DifferenceTraverser : public SetTraverserBase> + { + using Self = DifferenceTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + using Childrens = typename SetTraverserTraits::Childrens; + + template + using IthChild = std::tuple_element::type; + + static constexpr std::size_t nIntervals = std::tuple_size_v; + + DifferenceTraverser(const std::array& shifts, const SetTraversers&... set_traversers) + : m_min_start(std::numeric_limits::min()) + , m_set_traversers(set_traversers...) + , m_shifts(shifts) + { + compute_current_interval(); + } + + inline bool is_empty() const + { + return std::get<0>(m_set_traversers).is_empty(); + } + + inline void next_interval() + { + assert(!is_empty()); + advance_ref_interval(); + compute_current_interval(); + } + + inline current_interval_t current_interval() const + { + return m_current_interval; + } + + private: + + inline void advance_ref_interval() + { + if (m_current_interval.end != std::get<0>(m_set_traversers).current_interval().end << m_shifts[0]) + { + // we have removed the beginning of the current interval. + // so ve remove [m_current_interval.start, m_current_interval.end) from std::get<0>(m_set_traversers).current_interval() + m_min_start = m_current_interval.end; + } + else + { + // all of the current interval has been removed. + // move to the next one. + std::get<0>(m_set_traversers).next_interval(); + } + } + + inline void compute_current_interval() + { + while (!std::get<0>(m_set_traversers).is_empty() && !try_to_compute_current_interval()) + { + advance_ref_interval(); + } + } + + inline bool try_to_compute_current_interval() + { + assert(!std::get<0>(m_set_traversers).is_empty()); + + m_current_interval.start = std::max(m_min_start, std::get<0>(m_set_traversers).current_interval().start << m_shifts[0]); + m_current_interval.end = std::get<0>(m_set_traversers).current_interval().end << m_shifts[0]; + + static_for<1, nIntervals>::apply( + [this](const auto i) + { + IthChild& set_traverser = std::get(m_set_traversers); + + while (!set_traverser.is_empty() && (set_traverser.current_interval().end << m_shifts[i]) < m_current_interval.start) + { + set_traverser.next_interval(); + } + + if (!set_traverser.is_empty() && (set_traverser.current_interval().start << m_shifts[i]) <= m_current_interval.start) + { + m_current_interval.start = set_traverser.current_interval().end << m_shifts[i]; + m_min_start = m_current_interval.start; + set_traverser.next_interval(); + } + if (!set_traverser.is_empty() && (set_traverser.current_interval().start << m_shifts[i]) <= m_current_interval.end) + { + m_current_interval.end = set_traverser.current_interval().start << m_shifts[i]; + } + }); + + return m_current_interval.is_valid(); + } + + interval_t m_current_interval; + value_t m_min_start; + Childrens m_set_traversers; + const std::array& m_shifts; + }; + +} diff --git a/include/samurai/subset/traversers/intersection_traverser.hpp b/include/samurai/subset/traversers/intersection_traverser.hpp new file mode 100644 index 000000000..1e1997acd --- /dev/null +++ b/include/samurai/subset/traversers/intersection_traverser.hpp @@ -0,0 +1,105 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../utils.hpp" +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class IntersectionTraverser; + + template + struct SetTraverserTraits> + { + using Childrens = std::tuple; + using interval_t = typename SetTraverserTraits>::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class IntersectionTraverser : public SetTraverserBase> + { + using Self = IntersectionTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + using Childrens = typename SetTraverserTraits::Childrens; + + static constexpr std::size_t nIntervals = std::tuple_size_v; + + IntersectionTraverser(const std::array& shifts, const SetTraversers&... set_traverser) + : m_set_traversers(set_traverser...) + , m_shifts(shifts) + { + next_interval(); + } + + inline bool is_empty_impl() const + { + return !m_current_interval.is_valid(); + } + + inline void next_interval() + { + m_current_interval.start = 0; + m_current_interval.end = 0; + + while (not_is_any_child_empty() && m_current_interval.start >= m_current_interval.end) + { + m_current_interval.start = std::numeric_limits::min(); + m_current_interval.end = std::numeric_limits::max(); + + enumerate_const_items( + m_set_traversers, + [this](const auto i, const auto& set_traverser) + { + if (!set_traverser.is_empty()) + { + m_current_interval.start = std::max(m_current_interval.start, + set_traverser.current_interval().start << m_shifts[i]); + m_current_interval.end = std::min(m_current_interval.end, set_traverser.current_interval().end << m_shifts[i]); + } + }); + + enumerate_items( + m_set_traversers, + [this](const auto i, auto& set_traverser) + { + if (!set_traverser.is_empty() && ((set_traverser.current_interval().end << m_shifts[i]) == m_current_interval.end)) + { + set_traverser.next_interval(); + } + }); + } + } + + inline current_interval_t current_interval() const + { + return m_current_interval; + } + + private: + + inline bool not_is_any_child_empty() const + { + return std::apply( + [](const auto&... set_traversers) + { + return (!set_traversers.is_empty() and ...); + }, + m_set_traversers); + } + + interval_t m_current_interval; + Childrens m_set_traversers; + const std::array& m_shifts; + }; +} diff --git a/include/samurai/subset/traversers/lca_batch_traverser.hpp b/include/samurai/subset/traversers/lca_batch_traverser.hpp new file mode 100644 index 000000000..03ee0640c --- /dev/null +++ b/include/samurai/subset/traversers/lca_batch_traverser.hpp @@ -0,0 +1,80 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#include "../../level_cell_array.hpp" +#include "set_traverser_base.hpp" + +#pragma once + +namespace samurai +{ + template + class LCABatchTraverser; + + template + struct SetTraverserTraits> + { + using interval_t = typename LCA::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class LCABatchTraverser : public SetTraverserBase> + { + using Self = LCABatchTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + using vector_interval_iterator = typename std::vector::const_iterator; + using list_interval_iterator = typename std::vector::const_iterator; + + LCABatchTraverser(const vector_interval_iterator first, const vector_interval_iterator end) + : m_vector_first_interval(first) + , m_vector_end_interval(end) + , m_use_vector_iterator(true) + { + } + + LCABatchTraverser(const list_interval_iterator first, const list_interval_iterator end) + : m_list_first_interval(first) + , m_list_end_interval(end) + , m_use_vector_iterator(false) + { + } + + inline bool is_empty_impl() const + { + return m_use_vector_iterator ? m_vector_first_interval == m_vector_end_interval : m_list_first_interval == m_list_end_interval; + } + + inline void next_interval_impl() + { + assert(!is_empty_impl()); + if (m_use_vector_iterator) + { + ++m_vector_first_interval; + } + else + { + ++m_list_first_interval; + } + } + + inline current_interval_t current_interval_impl() const + { + return m_use_vector_iterator ? *m_vector_first_interval : *m_list_first_interval; + } + + private: + + vector_interval_iterator m_vector_first_interval; + vector_interval_iterator m_vector_end_interval; + list_interval_iterator m_list_first_interval; + list_interval_iterator m_list_end_interval; + bool m_use_vector_iterator; + }; +} diff --git a/include/samurai/subset/traversers/lca_traverser.hpp b/include/samurai/subset/traversers/lca_traverser.hpp new file mode 100644 index 000000000..d9a426c4a --- /dev/null +++ b/include/samurai/subset/traversers/lca_traverser.hpp @@ -0,0 +1,64 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#include "../../level_cell_array.hpp" +#include "set_traverser_base.hpp" + +#pragma once + +namespace samurai +{ + template + concept LCA_concept = std::same_as, T>; + + template + class LCATraverser; + + template + struct SetTraverserTraits> + { + using interval_t = typename LCA::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class LCATraverser : public SetTraverserBase> + { + using Self = LCATraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + using interval_iterator = typename std::vector::const_iterator; + + LCATraverser(const interval_iterator first, const interval_iterator end) + : m_first_interval(first) + , m_end_interval(end) + { + } + + inline bool is_empty_impl() const + { + return m_first_interval == m_end_interval; + } + + inline void next_interval_impl() + { + assert(!is_empty_impl()); + ++m_first_interval; + } + + inline current_interval_t current_interval_impl() const + { + return *m_first_interval; + } + + private: + + interval_iterator m_first_interval; + interval_iterator m_end_interval; + }; +} diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp new file mode 100644 index 000000000..fe952e846 --- /dev/null +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -0,0 +1,175 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../../samurai_config.hpp" +#include "../fixed_capacity_array.hpp" +#include "set_traverser_base.hpp" + +#include + +namespace samurai +{ + + enum class ProjectionType + { + COARSEN, + REFINE + }; + + template + class ProjectionTraverser; + + template + struct SetTraverserTraits> + { + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class ProjectionTraverser : public SetTraverserBase> + { + using Self = ProjectionTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + + ProjectionTraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) + : m_projectionType(projectionType) + , m_shift(shift) + , m_isEmpty(set_traverser.is_empty()) + { + m_set_traversers.push_back(set_traverser); + if (!m_isEmpty) + { + if (m_projectionType == ProjectionType::COARSEN) + { + m_current_interval.start = coarsen_start(m_set_traversers[0].current_interval()); + m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); + + m_set_traversers[0].next_interval(); + + // when coarsening, two disjoint intervals may be merged. + // we need to check if the next_interval overlaps + for (; !m_set_traversers[0].is_empty() && coarsen_start(m_set_traversers[0].current_interval()) <= m_current_interval.end; + m_set_traversers[0].next_interval()) + { + m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); + } + } + else + { + m_current_interval.start = m_set_traversers[0].current_interval().start << shift; + m_current_interval.end = m_set_traversers[0].current_interval().end << shift; + } + } + } + + /* + * This constructor only works for coarsening + */ + ProjectionTraverser(const FixedCapacityArray& set_traversers, const std::size_t shift) + : m_set_traversers(set_traversers) + , m_projectionType(ProjectionType::COARSEN) + , m_shift(shift) + { + next_interval_coarsen(); + } + + inline bool is_empty() const + { + return m_isEmpty; + } + + inline void next_interval() + { + assert(!is_empty()); + if (m_projectionType == ProjectionType::COARSEN) + { + next_interval_coarsen(); + } + else + { + m_set_traversers[0].next_interval(); + m_isEmpty = m_set_traversers[0].is_empty(); + if (!m_isEmpty) + { + m_current_interval.start = m_set_traversers[0].current_interval().start << m_shift; + m_current_interval.end = m_set_traversers[0].current_interval().end << m_shift; + } + } + } + + inline current_interval_t current_interval() const + { + return m_current_interval; + } + + private: + + inline void next_interval_coarsen() + { + m_current_interval.start = std::numeric_limits::max(); + // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift + for (const SetTraverser& set_traverser : m_set_traversers) + { + if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) < m_current_interval.start)) + { + m_current_interval.start = coarsen_start(set_traverser.current_interval()); + m_current_interval.end = coarsen_end(set_traverser.current_interval()); + } + } + // Now we find the end of the interval, i.e. the largest set_traverser.current_interval().end >> m_shift + // such that (set_traverser.current_interval().start >> m_shift) < m_current_interval.end + bool is_done = false; + while (!is_done) + { + is_done = true; + // advance set traverses that are behind current interval + for (SetTraverser& set_traverser : m_set_traversers) + { + while (!set_traverser.is_empty() && (coarsen_end(set_traverser.current_interval()) <= m_current_interval.end)) + { + set_traverser.next_interval(); + } + } + // try to find a new end + for (const SetTraverser& set_traverser : m_set_traversers) + { + // there is an overlap + if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) <= m_current_interval.end)) + { + is_done = false; + m_current_interval.end = coarsen_end(set_traverser.current_interval()); + } + } + } + m_isEmpty = (m_current_interval.start == std::numeric_limits::max()); + } + + inline value_t coarsen_start(const interval_t& interval) const + { + return interval.start >> m_shift; + } + + inline value_t coarsen_end(const interval_t& interval) const + { + const value_t trial_end = interval.end >> m_shift; + return (trial_end << m_shift) < interval.end ? trial_end + 1 : trial_end; + } + + //~ std::vector m_set_traversers; + FixedCapacityArray m_set_traversers; + ProjectionType m_projectionType; + std::size_t m_shift; + interval_t m_current_interval; + bool m_isEmpty; + }; + +} diff --git a/include/samurai/subset/traversers/set_traverser_base.hpp b/include/samurai/subset/traversers/set_traverser_base.hpp new file mode 100644 index 000000000..22995cd9d --- /dev/null +++ b/include/samurai/subset/traversers/set_traverser_base.hpp @@ -0,0 +1,55 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#include + +#include + +#pragma once + +namespace samurai +{ + template + struct SetTraverserTraits; + + template + class SetTraverserBase; + + template + concept SetTraverser_concept = std::is_base_of, T>::value; + + template + class SetTraverserBase + { + public: + + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = typename SetTraverserTraits::current_interval_t; + using value_t = typename interval_t::value_t; + + const Derived& derived_cast() const + { + return static_cast(*this); + } + + Derived& derived_cast() + { + return static_cast(*this); + } + + inline bool is_empty() const + { + return derived_cast().is_empty_impl(); + } + + inline void next_interval() + { + derived_cast().next_interval_impl(); + } + + inline current_interval_t current_interval() const + { + return derived_cast().current_interval_impl(); + } + }; +} diff --git a/include/samurai/subset/traversers/translation_traverser.hpp b/include/samurai/subset/traversers/translation_traverser.hpp new file mode 100644 index 000000000..f4577d065 --- /dev/null +++ b/include/samurai/subset/traversers/translation_traverser.hpp @@ -0,0 +1,61 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#include "set_traverser_base.hpp" + +#pragma once + +namespace samurai +{ + + template + class TranslationTraverser; + + template + struct SetTraverserTraits> + { + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = interval_t; + }; + + template + class TranslationTraverser : public SetTraverserBase> + { + using Self = TranslationTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + + TranslationTraverser(const SetTraverser& set_traverser, const value_t& translation) + : m_set_traverser(set_traverser) + , m_translation(translation) + { + } + + inline bool is_empty() const + { + return m_set_traverser.is_empty(); + } + + inline void next_interval() + { + assert(!is_empty()); + m_set_traverser.next_interval(); + } + + inline current_interval_t current_interval() const + { + return current_interval_t{m_set_traverser.current_interval().start + m_translation, + m_set_traverser.current_interval().end + m_translation}; + } + + private: + + SetTraverser m_set_traverser; + value_t m_translation; + }; +} diff --git a/include/samurai/subset/traversers/union_traverser.hpp b/include/samurai/subset/traversers/union_traverser.hpp new file mode 100644 index 000000000..1af2ec968 --- /dev/null +++ b/include/samurai/subset/traversers/union_traverser.hpp @@ -0,0 +1,106 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class UnionTraverser; + + template + struct SetTraverserTraits> + { + using Childrens = std::tuple; + using interval_t = typename SetTraverserTraits>::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class UnionTraverser : public SetTraverserBase> + { + using Self = UnionTraverser; + using Base = SetTraverserBase; + + public: + + using interval_t = typename Base::interval_t; + using current_interval_t = typename Base::current_interval_t; + using value_t = typename Base::value_t; + using Childrens = typename SetTraverserTraits::Childrens; + + static constexpr std::size_t nIntervals = std::tuple_size_v; + + UnionTraverser(const std::array& shifts, const SetTraversers&... set_traversers) + : m_set_traversers(set_traversers...) + , m_shifts(shifts) + { + next_interval(); + } + + inline bool is_empty() const + { + return m_current_interval.start == std::numeric_limits::max(); + } + + inline void next_interval() + { + m_current_interval.start = std::numeric_limits::max(); + // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start << m_shifts[i] + enumerate_const_items( + m_set_traversers, + [this](const auto i, const auto& set_traverser) + { + if (!set_traverser.is_empty() && ((set_traverser.current_interval().start << m_shifts[i]) < m_current_interval.start)) + { + m_current_interval.start = set_traverser.current_interval().start << m_shifts[i]; + m_current_interval.end = set_traverser.current_interval().end << m_shifts[i]; + } + }); + // Now we find the end of the interval, i.e. the largest set_traverser.current_interval().end << m_shifts[i] + // such that (set_traverser.current_interval().start << m_shifts[i]) < m_current_interval.end + bool is_done = false; + while (!is_done) + { + is_done = true; + // advance set traverses that are behind current interval + enumerate_items( + m_set_traversers, + [this](const auto i, auto& set_traverser) + { + while (!set_traverser.is_empty() && (set_traverser.current_interval().end << m_shifts[i]) <= m_current_interval.end) + { + set_traverser.next_interval(); + } + }); + // try to find a new end + enumerate_const_items( + m_set_traversers, + [&is_done, this](const auto i, const auto& set_traverser) + { + // there is an overlap + if (!set_traverser.is_empty() && (set_traverser.current_interval().start << m_shifts[i]) <= m_current_interval.end) + { + is_done = false; + m_current_interval.end = set_traverser.current_interval().end << m_shifts[i]; + } + }); + } + } + + inline current_interval_t current_interval() const + { + return m_current_interval; + } + + private: + + interval_t m_current_interval; + Childrens m_set_traversers; + const std::array& m_shifts; + }; + +} diff --git a/include/samurai/subset/utils.hpp b/include/samurai/subset/utils.hpp index 4c774c8ef..3b5c95456 100644 --- a/include/samurai/subset/utils.hpp +++ b/include/samurai/subset/utils.hpp @@ -3,73 +3,55 @@ #pragma once -#include -#include -#include -#include +#include +#include -// namespace samurai::experimental namespace samurai { - template - static constexpr T sentinel = std::numeric_limits::max(); - - template - inline T end_shift(T value, T shift) + //////////////////////////////////////////////////////////////////////// + //// misc + //////////////////////////////////////////////////////////////////////// + template + const T& vmin(const T& a) { - return shift >= 0 ? value << shift : ((value - 1) >> -shift) + 1; + return a; } - template - inline T start_shift(T value, T shift) + template + const T& vmax(const T& a) { - return shift >= 0 ? value << shift : value >> -shift; + return a; } - constexpr auto compute_min(auto const& value, auto const&... args) + template + T vmin(const T& a, const T& b, const Ts&... others) { - if constexpr (sizeof...(args) == 0u) // Single argument case! + if constexpr (sizeof...(Ts) == 0u) { - return value; + return std::min(a, b); } - else // For the Ts... + else { - const auto min = compute_min(args...); - return value < min ? value : min; + return a < b ? vmin(a, others...) : vmin(b, others...); } } - constexpr auto compute_max(auto const& value, auto const&... args) + template + T vmax(const T& a, const T& b, const Ts&... others) { - if constexpr (sizeof...(args) == 0u) // Single argument case! + if constexpr (sizeof...(Ts) == 0u) { - return value; + return std::max(a, b); } - else // For the Ts... + else { - const auto max = compute_max(args...); - return value > max ? value : max; + return a > b ? vmax(a, others...) : vmax(b, others...); } } - template - struct get_interval_type - { - using type = typename S1::interval_t; - }; - - template - using get_interval_t = typename get_interval_type::type; - - template - struct get_set_dim - { - static constexpr std::size_t value = S1::dim; - }; - - template - constexpr std::size_t get_set_dim_v = get_set_dim...>::value; - + //////////////////////////////////////////////////////////////////////// + //// intervals args + //////////////////////////////////////////////////////////////////////// template ::value_type::value_type> ForwardIt lower_bound_interval(ForwardIt begin, ForwardIt end, const T& value) { @@ -94,20 +76,41 @@ namespace samurai }); } - template - constexpr void zip_apply_impl(F&& f, Tuple1&& t1, Tuple2&& t2, std::index_sequence) + //////////////////////////////////////////////////////////////////////// + //// tuple iteration + //////////////////////////////////////////////////////////////////////// + namespace detail { - (f(std::get(std::forward(t1)), std::get(std::forward(t2))), ...); + template + Func enumerate_items(Tuple& tuple, Func func, std::index_sequence) + { + (func(Is, std::get(tuple)), ...); + return func; + } + + template + Func enumerate_const_items(const Tuple& tuple, Func func, std::index_sequence) + { + (func(Is, std::get(tuple)), ...); + return func; + } } - template - constexpr void zip_apply(F&& f, Tuple1&& t1, Tuple2&& t2) + template + Func enumerate_items(Tuple& tuple, Func func) { - constexpr std::size_t size1 = std::tuple_size_v>; - constexpr std::size_t size2 = std::tuple_size_v>; + constexpr std::size_t N = std::tuple_size_v>; - static_assert(size1 == size2, "Tuples must have the same size"); + return detail::enumerate_items(tuple, func, std::make_index_sequence{}); + } + + template + Func enumerate_const_items(const Tuple& tuple, Func func) + { + constexpr std::size_t N = std::tuple_size_v>; - zip_apply_impl(std::forward(f), std::forward(t1), std::forward(t2), std::make_index_sequence{}); + return detail::enumerate_const_items(tuple, func, std::make_index_sequence{}); } + + //////////////////////////////////////////////////////////////////////// } diff --git a/include/samurai/subset/visitor.hpp b/include/samurai/subset/visitor.hpp deleted file mode 100644 index 507c59f3f..000000000 --- a/include/samurai/subset/visitor.hpp +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include - -#include "utils.hpp" - -namespace samurai -{ - template - class IntervalListRange - { - public: - - using container_t = container_; - using value_t = typename container_t::value_type; - using iterator_t = typename container_t::const_iterator; - - IntervalListRange(const container_t& data, std::ptrdiff_t start, std::ptrdiff_t end) - : m_data(data) - , m_work(data) - , m_begin(data.cbegin() + start) - , m_end(data.cbegin() + end) - { - } - - IntervalListRange(const container_t& data, const container_t& w) - : m_data(data) - , m_work(w) - , m_begin(w.cbegin()) - , m_end(w.cend()) - { - } - - inline auto begin() const - { - return m_begin; - } - - inline auto end() const - { - return m_end; - } - - private: - - const container_t& m_data; - const container_t& m_work; - iterator_t m_begin; - iterator_t m_end; - }; - - template - class IntervalListVisitor - { - public: - - using container_t = container_; - using base_t = IntervalListRange; - using iterator_t = typename base_t::iterator_t; - using interval_t = typename base_t::value_t; - using value_t = typename interval_t::value_t; - - IntervalListVisitor(auto lca_level, auto level, auto max_level, const IntervalListRange& intervals) - : m_lca_level(static_cast(lca_level)) - , m_shift2dest(static_cast(max_level) - static_cast(level)) - , m_shift2ref(static_cast(max_level) - static_cast(lca_level)) - , m_intervals(intervals) - , m_first(intervals.begin()) - , m_last(intervals.end()) - , m_current(std::numeric_limits::min()) - , m_is_start(true) - { - } - - explicit IntervalListVisitor(IntervalListRange&& intervals) - : m_lca_level(std::numeric_limits::infinity()) - , m_shift2dest(std::numeric_limits::infinity()) - , m_shift2ref(std::numeric_limits::infinity()) - , m_intervals(std::move(intervals)) - , m_first(m_intervals.begin()) - , m_last(m_intervals.end()) - , m_current(sentinel) - , m_is_start(true) - { - } - - template - inline auto start(const auto& it, Func& start_fct) const - { - auto i = it->start << m_shift2ref; - return start_fct(m_lca_level, i, 0); - } - - template - inline auto end(const auto& it, Func& end_fct) const - { - auto i = it->end << m_shift2ref; - return end_fct(m_lca_level, i, 1); - } - - inline bool is_in(auto scan) const - { - // Recall that we check if scan is inside an interval defined as [start, - // end[. The end of the interval is not included. - // - // if the m_current value is the start of the interval which means m_is_start = - // true then if scan is lower than m_current, scan is not in the - // interval. - // - // if the m_current value is the end of the interval which means m_is_start = false - // then if scan is lower than m_current, scan is in the interval. - return m_current != sentinel && !((scan < m_current) ^ (!m_is_start)); - } - - inline bool is_empty() const - { - return m_current == sentinel; - } - - inline auto min() const - { - return m_current; - } - - inline auto shift() const - { - return m_shift2dest; - } - - template - inline void next_interval(StartEnd& start_and_stop) - { - auto& [start_fct, end_fct] = start_and_stop; // cppcheck-suppress variableScope - - auto i_start = start(m_first, start_fct); - auto i_end = end(m_first, end_fct); - while (m_first + 1 != m_last && i_end >= start(m_first + 1, start_fct)) - { - ++m_first; - i_end = end(m_first, end_fct); - } - m_current_interval = {i_start, i_end}; - - if (m_current_interval.is_valid()) - { - m_current = m_current_interval.start; - } - else - { - m_current = sentinel; - } - } - - template - inline void next(auto scan, StartEnd& start_and_stop) - { - if (m_current == std::numeric_limits::min()) - { - next_interval(start_and_stop); - return; - } - - if (m_current == scan) - { - if (m_is_start) - { - m_current = m_current_interval.end; - } - else - { - ++m_first; - - if (m_first == m_last) - { - m_current = sentinel; - return; - } - next_interval(start_and_stop); - } - m_is_start = !m_is_start; - } - } - - private: - - int m_lca_level; - int m_shift2dest; - int m_shift2ref; - IntervalListRange m_intervals; - iterator_t m_first; - iterator_t m_last; - value_t m_current; - interval_t m_current_interval; - bool m_is_start; - }; - - template - class SetTraverser - { - public: - - static constexpr std::size_t dim = get_set_dim_v; - using set_type = std::tuple; - using interval_t = get_interval_t; - - SetTraverser(int shift, const Operator& op, S&&... s) - : m_shift(shift) - , m_operator(op) - , m_s(std::forward(s)...) - { - } - - inline auto shift() const - { - return m_shift; - } - - inline bool is_in(auto scan) const - { - return std::apply( - [this, scan](auto&&... args) - { - return m_operator.is_in(scan, args...); - }, - m_s); - } - - inline bool is_empty() const - { - return std::apply( - [this](auto&&... args) - { - return m_operator.is_empty(args...); - }, - m_s); - } - - inline auto min() const - { - return std::apply( - [](auto&&... args) - { - return compute_min(args.min()...); - }, - m_s); - } - - template - void next(auto scan, StartEnd&& start_and_stop) - { - zip_apply( - [scan](auto& arg, auto& start_end_fct) - { - arg.next(scan, start_end_fct); - }, - m_s, - std::forward(start_and_stop)); - } - - private: - - int m_shift; - Operator m_operator; - set_type m_s; - }; - - struct IntersectionOp - { - bool is_in(auto scan, const auto&... args) const - { - return (args.is_in(scan) && ...); - } - - bool is_empty(const auto&... args) const - { - return (args.is_empty() || ...); - } - - bool exist(const auto&... args) const - { - return (args.exist() && ...); - } - }; - - struct UnionOp - { - bool is_in(auto scan, const auto&... args) const - { - return (args.is_in(scan) || ...); - } - - bool is_empty(const auto&... args) const - { - return (args.is_empty() && ...); - } - - bool exist(const auto&... args) const - { - return (args.exist() || ...); - } - }; - - struct DifferenceOp - { - bool is_in(auto scan, const auto& arg, const auto&... args) const - { - return arg.is_in(scan) && !(args.is_in(scan) || ...); - } - - bool is_empty(const auto& arg, const auto&...) const - { - return arg.is_empty(); - } - - bool exist(const auto& arg, const auto&...) const - { - return arg.exist(); - } - }; - - struct Difference2Op - { - bool is_in(auto scan, const auto& arg, const auto&...) const - { - return arg.is_in(scan); - } - - bool is_empty(const auto& arg, const auto&...) const - { - return arg.is_empty(); - } - - bool exist(const auto& arg, const auto&...) const - { - return arg.exist(); - } - }; - - template - auto get_operator(const operator_t& op) - { - return op; - } - - template - auto get_operator(const DifferenceOp& op) - { - if constexpr (d == 1) - { - return op; - } - else - { - return Difference2Op(); - } - } - - struct SelfOp - { - bool is_in(auto scan, const auto& arg) const - { - return arg.is_in(scan); - } - - bool is_empty(const auto& arg) const - { - return arg.is_empty(); - } - - bool exist(const auto& arg) const - { - return arg.exist(); - } - }; -} diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 1528938d4..bb011b38f 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -144,9 +144,9 @@ namespace samurai TEST(subset, compute_min) { - EXPECT_EQ(1, compute_min(3, 4, 1, 4)); - EXPECT_EQ(0, compute_min(0, 0, 0, 0)); - EXPECT_EQ(-1, compute_min(-1, -1, -1, -1)); + EXPECT_EQ(1, vmin(3, 4, 1, 4)); + EXPECT_EQ(0, vmin(0, 0, 0, 0)); + EXPECT_EQ(-1, vmin(-1, -1, -1, -1)); } TEST(subset, check_dim) From 4d876c61653d19e0b0924cb827aacb06af8cf82b Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 17 Sep 2025 15:04:54 +0200 Subject: [PATCH 02/28] FixedCapacityArray corrected --- include/samurai/subset/apply.hpp | 10 +- include/samurai/subset/box_view.hpp | 74 ++++------ include/samurai/subset/contraction.hpp | 73 +++++---- .../samurai/subset/fixed_capacity_array.hpp | 128 +++++++++++----- include/samurai/subset/lca_view.hpp | 80 +++++----- include/samurai/subset/nary_set_operator.hpp | 138 ++++++++---------- include/samurai/subset/node.hpp | 5 +- include/samurai/subset/projection.hpp | 123 ++++++---------- include/samurai/subset/set_base.hpp | 46 +++--- include/samurai/subset/translation.hpp | 66 ++++----- .../subset/traversers/box_traverser.hpp | 64 ++++---- .../traversers/contraction_traverser.hpp | 44 +++--- .../traversers/difference_id_traverser.hpp | 43 +++--- .../traversers/difference_traverser.hpp | 71 +++++---- .../traversers/intersection_traverser.hpp | 62 ++++---- .../subset/traversers/lca_batch_traverser.hpp | 80 ---------- .../subset/traversers/lca_traverser.hpp | 50 +++---- .../traversers/projection_traverser.hpp | 73 +++++---- .../subset/traversers/set_traverser_base.hpp | 21 ++- .../traversers/translation_traverser.hpp | 50 +++---- .../subset/traversers/union_traverser.hpp | 58 ++++---- include/samurai/subset/utils.hpp | 3 +- tests/test_subset.cpp | 7 +- 23 files changed, 622 insertions(+), 747 deletions(-) delete mode 100644 include/samurai/subset/traversers/lca_batch_traverser.hpp diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index 0d234a185..5e1978220 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -9,8 +9,8 @@ namespace samurai { namespace detail { - template - void apply_rec(const Set& set, Func&& func, Index& index, std::integral_constant d_ic) + template + void apply_rec(const SetBase& set, Func&& func, Index& index, std::integral_constant d_ic) { using traverser_t = typename Set::template traverser_t; using current_interval_t = typename traverser_t::current_interval_t; @@ -33,10 +33,10 @@ namespace samurai } } - template - void apply(const Set& set, Func&& func) + template + void apply(const SetBase& set, Func&& func) { - constexpr std::size_t dim = SetTraits::getDim(); + constexpr std::size_t dim = Set::dim; xt::xtensor_fixed> index; if (set.exist()) diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 3a988534b..19347f8fa 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -8,77 +8,65 @@ namespace samurai { - template + + template class BoxView; - template + template struct SetTraits> { + static_assert(std::same_as, B>); + template using traverser_t = BoxTraverser; - - static constexpr std::size_t getDim() - { - return B::dim; - } + + static constexpr std::size_t dim = B::dim; }; - template + template class BoxView : public SetBase> { using Self = BoxView; - using Base = SetBase; - - public: - - template - using traverser_t = typename Base::template traverser_t; - - BoxView(const std::size_t level_impl, const B& box) - : m_level_impl(level_impl) + public: + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + BoxView(const std::size_t level, const B& box) + : m_level(level) , m_box(box) { } - - std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_level_impl; + return m_level; } - bool exist_impl() const + inline bool exist_impl() const { - return m_box.is_valid(); + return m_box.is_valid(); } - bool empty_impl() const + inline bool empty_impl() const { - return !exist_impl(); + return !exist_impl(); } - + template - traverser_t get_traverser_impl([[maybe_unused]] const index_t& index, std::integral_constant) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const { - if constexpr (d != Base::dim - 1) + if constexpr (d != dim - 1) { assert(m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]); } - return traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]); + return traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]); } + + private: - private: - - std::size_t m_level_impl; + std::size_t m_level; const B& m_box; - }; - - template - struct SelfTraits { using Type = BoxView; }; - - template - BoxView self(const B& box) - { - return BoxView(box); - } - -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index e4f7fdef0..1d33a017d 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -9,35 +9,30 @@ namespace samurai { - template + template class Contraction; - template + template struct SetTraits> { + static_assert(IsSet::value); + template using traverser_t = ContractionTraverser>; - - static constexpr std::size_t getDim() - { - return SetTraits::getDim(); - } + + static constexpr std::size_t dim = Set::dim; }; - template + template class Contraction : public SetBase> { using Self = Contraction; - using Base = SetBase; - - public: - - template - using traverser_t = typename Base::template traverser_t; + public: + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS - using value_t = typename Base::value_t; - using contraction_t = std::array; - using do_contraction_t = std::array; + using contraction_t = std::array; + using do_contraction_t = std::array; Contraction(const Set& set, const contraction_t& contraction) : m_set(set) @@ -67,49 +62,49 @@ namespace samurai } } - - std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_set.level_impl(); + return m_set.level(); } - bool exist_impl() const + inline bool exist_impl() const { - return m_set.exist_impl(); + return m_set.exist(); } - bool empty_impl() const + inline bool empty_impl() const { - return m_set.empty_impl(); + return m_set.empty(); } - + template - traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return traverser_t(m_set.get_traverser_impl(index, d_ic), m_contraction[d]); + return traverser_t(m_set.get_traverser(index, d_ic), m_contraction[d]); } - - private: - + + private: Set m_set; contraction_t m_contraction; - }; - + }; + template - auto contract(const Set& set, const typename Contraction::Type>::contraction_t& contraction) + auto contract(const Set& sets, const typename Contraction>::contraction_t& contraction) { - return Contraction(self(set), contraction); + return Contraction(self(sets), contraction); } template - auto contract(const Set& set, const typename Contraction::Type>::value_t contraction) + auto contract(const Set& sets, const typename Contraction>::value_t contraction) { - return Contraction(self(set), contraction); + return Contraction(self(sets), contraction); } template - auto contract(const Set& set, const typename Contraction::Type>::value_t contraction, const typename Contraction::Type>::do_contraction_t& do_contraction) + auto contract(const Set& sets, const typename Contraction>::value_t contraction, const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this more readable, perhaps a traits... { - return Contraction(self(set), contraction, do_contraction); + return Contraction(self(sets), contraction, do_contraction); } -} + +} // namespace samurai diff --git a/include/samurai/subset/fixed_capacity_array.hpp b/include/samurai/subset/fixed_capacity_array.hpp index 299fa11a1..01ec6210b 100644 --- a/include/samurai/subset/fixed_capacity_array.hpp +++ b/include/samurai/subset/fixed_capacity_array.hpp @@ -3,64 +3,80 @@ #pragma once -template -class FixedCapacityNonTrivialStorage -{ - static_assert(not std::is_trivially_constructible::value); -public: - constexpr T* data() { return reinterpret_cast< T*>(m_core.data()); } - constexpr const T* data() const { return reinterpret_cast(m_core.data()); } -private: - std::array m_core; -}; - #include #include template class FixedCapacityArray { - using Storage = std::conditional_t< std::is_trivially_constructible::value, std::array, FixedCapacityNonTrivialStorage >; + using CoreElement = std::conditional_t< std::is_trivially_constructible::value, T, std::aligned_storage_t >; public: - FixedCapacityArray() : m_end(m_storage.data()) {} + FixedCapacityArray() noexcept : m_end(begin()) {} FixedCapacityArray(const std::size_t size, const T& value = T()) requires(std::is_trivially_constructible::value) { - assert(size <= N); - m_end = begin() + size; - std::fill(begin(), end(), value); + assert(size <= N); + m_end = begin() + size; + for (T* it = begin(); it!=end(); ++it) + { + std::construct_at(it, value); + } + } + + FixedCapacityArray(const FixedCapacityArray& other) + { + copyFrom(std::cbegin(other), std::cend(other)); } - template - FixedCapacityArray(const FixedCapacityArray& other) requires(N2 <= N) - : m_end(m_storage.data() + other.size()) + FixedCapacityArray(FixedCapacityArray&& other) noexcept { - if constexpr (std::is_fundamental::value) + moveFrom(std::cbegin(other), std::cend(other)); + other.clear(); + } + + ~FixedCapacityArray() { clear(); } + + FixedCapacityArray& operator=(const FixedCapacityArray& other) + { + if (this != std::addressof(other)) { - std::copy(std::cbegin(other), std::cend(other), begin()); + clear(); + copyFrom(std::cbegin(other), std::cend(other), begin()); } - else + return *this; + } + + FixedCapacityArray& operator=(FixedCapacityArray&& other) noexcept + { + if (this != std::addressof(other)) { - const T* srcIt = std::cbegin(other); - for (T* dstIt = begin(); dstIt != end(); ++dstIt, ++srcIt) - { - std::construct_at(dstIt, *srcIt); - } - } + clear(); + moveFrom(std::cbegin(other), std::cend(other), begin()); + other.clear(); + } + return *this; } - ~FixedCapacityArray() { clear(); } + T* begin() noexcept + { + if constexpr (std::is_trivially_constructible::value) { return m_core.data(); } + else { return reinterpret_cast(m_core.data()); } + } + T* end() { return m_end; } - T* begin() { return m_storage.data(); } - T* end() { return m_end; } + const T* begin() const noexcept + { + if constexpr (std::is_trivially_constructible::value) { return m_core.data(); } + else { return reinterpret_cast(m_core.data()); } + } - const T* begin() const { return m_storage.data(); } - const T* end() const { return m_end; } + const T* end() const { return m_end; } const T& operator[](const std::size_t i) const { return *(begin() + i); } T& operator[](const std::size_t i) { return *(begin() + i); } - std::size_t size() const { return end() - begin(); } + std::ptrdiff_t ssize() const { return std::distance(begin(), end()); } + std::size_t size() const { return std::size_t(ssize()); } constexpr std::size_t capacity() const { return N; } @@ -85,10 +101,48 @@ class FixedCapacityArray void clear() { - std::destroy(begin(), end()); + if constexpr (not std::is_trivially_destructible_v) + { + std::destroy(begin(), end()); + } m_end = begin(); } private: - Storage m_storage; - T* m_end; + void copyFrom(const T* srcBegin, const T* srcEnd) + { + if constexpr (std::is_trivially_copyable::value) + { + std::copy(srcBegin, srcEnd, begin()); + m_end = begin() + std::distance(srcBegin, srcEnd); + } + else + { + m_end = begin(); + for (const T* srcIt = srcBegin; srcIt!=srcEnd; ++srcIt, ++m_end) + { + std::construct_at(m_end, *srcIt); + } + + } + } + + void moveFrom(const T* srcBegin, const T* srcEnd) + { + if constexpr (std::is_trivially_move_constructible::value) + { + std::move(srcBegin, srcEnd, begin()); + m_end = begin() + std::distance(srcBegin, srcEnd); + } + else + { + m_end = begin(); + for (const T* srcIt = srcBegin; srcIt!=srcEnd; ++srcIt, ++m_end) + { + std::construct_at(m_end, std::move(*srcIt)); + } + } + } + + std::array m_core; + T* m_end; }; diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 566659e46..b2bf72f98 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -8,56 +8,50 @@ namespace samurai { - template + + template class LCAView; - template + template struct SetTraits> { + static_assert(std::same_as, LCA>); + template using traverser_t = LCATraverser; - - static constexpr std::size_t getDim() - { - return LCA::dim; - } + + static constexpr std::size_t dim = LCA::dim; }; - template + template class LCAView : public SetBase> { using Self = LCAView; - using Base = SetBase; - - public: - - template - using traverser_t = typename Base::template traverser_t; - - explicit LCAView(const LCA& lca) - : m_lca(lca) + public: + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + LCAView(const LCA& lca) : m_lca(lca) {} + + inline std::size_t level_impl() const { + return m_lca.level(); } - std::size_t level_impl() const + inline bool exist_impl() const { - return m_lca.level(); + return !empty_impl(); } - bool exist_impl() const + inline bool empty_impl() const { - return !empty_impl(); + return m_lca.empty(); } - - bool empty_impl() const - { - return m_lca.empty(); - } - + template - traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const { - if constexpr (d != Base::dim - 1) + if constexpr (d != dim - 1) { const auto& y = index[d]; const auto& y_intervals = m_lca[d + 1]; @@ -72,6 +66,7 @@ namespace samurai if (y_interval_it != y_intervals.cend()) { const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); + return traverser_t(m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]), m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1])); } @@ -85,19 +80,16 @@ namespace samurai return traverser_t(m_lca[d].cbegin(), m_lca[d].cend()); } } - - private: - - const LCA& m_lca; - }; - template - struct SelfTraits { using Type = LCAView; }; - - template - LCAView self(const LCA& lca) - { - return LCAView(lca); - } - -} + private: + const LCA& m_lca; + }; + + + template + LCAView> self(const LevelCellArray& lca) + { + return LCAView>(lca); + } + +} // namespace samurai diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 8fbef7a26..987eaaba2 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -3,12 +3,12 @@ #pragma once +#include "set_base.hpp" #include "traversers/difference_id_traverser.hpp" #include "traversers/difference_traverser.hpp" #include "traversers/intersection_traverser.hpp" #include "traversers/union_traverser.hpp" - -#include "set_base.hpp" +#include "utils.hpp" namespace samurai { @@ -18,151 +18,140 @@ namespace samurai INTERSECTION, DIFFERENCE }; - - template + + template class NArySetOperator; - template + template struct SetTraits> { - using Childrens = std::tuple; + static_assert((IsSet::value and ...)); - template + template using traverser_t = UnionTraverser...>; - - static constexpr std::size_t getDim() - { - return SetTraits>::getDim(); - } + + static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; }; - template + template struct SetTraits> { - using Childrens = std::tuple; - - template - using traverser_t = IntersectionTraverser::template traverser_t...>; - - static constexpr std::size_t getDim() - { - return SetTraits>::getDim(); - } + static_assert((IsSet::value and ...)); + + template + using traverser_t = IntersectionTraverser...>; + + static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; }; - template + template struct SetTraits> { - using Childrens = std::tuple; - - template + static_assert((IsSet::value and ...)); + + template using traverser_t = std::conditional_t...>, DifferenceIdTraverser...>>; - - static constexpr std::size_t getDim() - { - return SetTraits>::getDim(); - } + + static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; }; - - template + + template class NArySetOperator : public SetBase> { - using Self = NArySetOperator; - using Base = SetBase; - using Childrens = typename SetTraits::Childrens; - - public: - - template - using traverser_t = typename Base::template traverser_t; - - static constexpr std::size_t nIntervals = std::tuple_size_v; - - explicit NArySetOperator(const Sets&... sets) + using Self = NArySetOperator; + public: + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + using Childrens = std::tuple; + + static constexpr std::size_t nIntervals = std::tuple_size_v; + + explicit NArySetOperator(const Sets&... sets) : m_sets(sets...) { - m_level_impl = std::apply( + m_level = std::apply( [](const auto&... set) -> std::size_t { - return vmax(set.level_impl()...); + return vmax(set.level()...); }, m_sets); enumerate_const_items(m_sets, [this](const auto i, const auto& set) { - m_shifts[i] = std::size_t(m_level_impl - set.level_impl()); + m_shifts[i] = std::size_t(m_level - set.level()); }); } - - std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_level_impl; + return m_level; } - bool exist_impl() const + inline bool exist_impl() const { - return std::apply( + return std::apply( [](const auto first_set, const auto&... other_sets) -> std::size_t { if constexpr (op == SetOperator::UNION) { - return first_set.exist_impl() || (other_sets.exist_impl() || ...); + return first_set.exist() || (other_sets.exist() || ...); } else if constexpr (op == SetOperator::INTERSECTION) { - return first_set.exist_impl() && (other_sets.exist_impl() && ...); + return first_set.exist() && (other_sets.exist() && ...); } else { - return first_set.exist_impl(); + return first_set.exist(); } }, m_sets); } - bool empty_impl() const + inline bool empty_impl() const { return std::apply( - [this](const auto first_set, const auto&... other_sets) -> std::size_t + [](const auto first_set, const auto&... other_sets) -> std::size_t { if constexpr (op == SetOperator::UNION) { - return first_set.empty_impl() && (other_sets.empty_impl() && ...); + return first_set.empty() && (other_sets.empty() && ...); } else if constexpr (op == SetOperator::INTERSECTION) { - return first_set.empty_impl() || (other_sets.empty_impl() || ...); + return first_set.empty() || (other_sets.empty() || ...); } else { - return first_set.empty_impl(); + return first_set.empty(); } }, m_sets); } - + template - traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return get_traverser_impl_impl(index, d_ic, std::make_index_sequence{}); + return get_traverser_impl_impl(index, d_ic, std::make_index_sequence{}); } - - private: + + private: template traverser_t get_traverser_impl_impl(const index_t& index, std::integral_constant d_ic, std::index_sequence) const { - return traverser_t(m_shifts, std::get(m_sets).get_traverser_impl(index >> m_shifts[Is], d_ic)...); + return traverser_t(m_shifts, std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic)...); } Childrens m_sets; - std::size_t m_level_impl; + std::size_t m_level; std::array m_shifts; - }; - + }; + //////////////////////////////////////////////////////////////////////// //// functions //////////////////////////////////////////////////////////////////////// @@ -171,8 +160,7 @@ namespace samurai auto union_(const Sets&... sets) requires(sizeof...(Sets) >= 1) { - //~ using Union = NArySetOperator...>; - using Union = NArySetOperator::Type...>; + using Union = NArySetOperator...>; return Union(self(sets)...); } @@ -181,7 +169,7 @@ namespace samurai auto intersection(const Sets&... sets) requires(sizeof...(Sets) >= 2) { - using Intersection = NArySetOperator::Type...>; + using Intersection = NArySetOperator...>; return Intersection(self(sets)...); } @@ -190,9 +178,9 @@ namespace samurai auto difference(const Sets&... sets) requires(sizeof...(Sets) >= 2) { - using Difference = NArySetOperator::Type...>; + using Difference = NArySetOperator...>; return Difference(self(sets)...); } - + } // namespace samurai diff --git a/include/samurai/subset/node.hpp b/include/samurai/subset/node.hpp index cc1a00278..43771ffd1 100644 --- a/include/samurai/subset/node.hpp +++ b/include/samurai/subset/node.hpp @@ -3,11 +3,12 @@ #pragma once +#include "set_base.hpp" +#include "projection.hpp" #include "apply.hpp" #include "box_view.hpp" -#include "lca_view.hpp" #include "contraction.hpp" -#include "set_base.hpp" +#include "lca_view.hpp" #include "nary_set_operator.hpp" #include "translation.hpp" #include "utils.hpp" diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 18215f6fd..d196d298f 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -3,143 +3,108 @@ #pragma once -#include - -#include -#include - +#include "../samurai_config.hpp" +#include "set_base.hpp" #include "traversers/projection_traverser.hpp" namespace samurai { - template + + + template class Projection; template struct SetTraits> { + static_assert(IsSet::value); + template - using traverser_t = ProjectionTraverser>; - - static constexpr std::size_t getDim() - { - return SetTraits::getDim(); - } + using traverser_t = std::conditional_t, 1>, + ProjectionTraverser, default_config::max_level>>; + + static constexpr std::size_t dim = Set::dim; }; - namespace detail - { - template struct Work; - - template - struct Work< Set, std::index_sequence > - { - template - using WorkElement = std::vector< typename Set::template traverser_t >; - - using Type = std::tuple< WorkElement... >; - }; - } - - template - using Work = typename detail::Work< Set, std::make_index_sequence::getDim()> >::Type; - - /* - * The main issue with projection, Coarsening specifically, is that - * the interval is extended upon projection e.g. both - * Proj([1,4),1,0) and Proj([0,3),1,0) results in [0, 2) - * It means the coarsening operation, unlike the translation e.g., - * is a unary, NON BIJECTIVE operation. - * Thus in more than 1d, if I'm projecting over more than 1 level_impl: - * Proj([5, 17), [18, 20), 2, 0) = [1, 3) - * So given a y_proj in [1, 3), we need to traverse accross multiple - * y. - * y_proj = 1 => y \in [4, 8) - * y_proj = 2 => y \in [8, 12) - * - */ template class Projection : public SetBase> { using Self = Projection; - using Base = SetBase; - - public: - - template - using traverser_t = typename Base::template traverser_t; - - using value_t = typename Base::value_t; - - Projection(const Set& set, const std::size_t level_impl) + public: + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + Projection(const Set& set, const std::size_t level) : m_set(set) - , m_level_impl(level_impl) + , m_level(level) { - if (m_level_impl < m_set.level_impl()) + if (m_level < m_set.level()) { m_projectionType = ProjectionType::COARSEN; - m_shift = m_set.level_impl() - m_level_impl; + m_shift = m_set.level() - m_level; } else { m_projectionType = ProjectionType::REFINE; - m_shift = m_level_impl - m_set.level_impl(); + m_shift = m_level - m_set.level(); } } - - std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_level_impl; + return m_level; } - bool exist_impl() const + inline bool exist_impl() const { - return m_set.exist_impl(); + return m_set.exist(); } - bool empty_impl() const + inline bool empty_impl() const { - return m_set.empty_impl(); + return m_set.empty(); } - + template - traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const { - if (m_projectionType == ProjectionType::COARSEN) + if (m_projectionType == ProjectionType::COARSEN) { - if constexpr (d != Base::dim - 1) + if constexpr (d != dim - 1) { const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; - xt::xtensor_fixed> index(_index << m_shift); + xt::xtensor_fixed> index(_index << m_shift); - //~ std::vector::template traverser_t> set_traversers; + //~ std::vector> set_traversers; //~ set_traversers.reserve(size_t(ymax - ymin)); - FixedCapacityArray::template traverser_t, default_config::max_level> set_traversers; + FixedCapacityArray, default_config::max_level> set_traversers; for (index[d] = ymin; index[d] != ymax; ++index[d]) { - set_traversers.push_back(m_set.get_traverser_impl(index, d_ic)); + set_traversers.push_back(m_set.get_traverser(index, d_ic)); } return traverser_t(set_traversers, m_shift); } else { - return traverser_t(m_set.get_traverser_impl(_index << m_shift, d_ic), m_projectionType, m_shift); + return traverser_t(m_set.get_traverser(_index << m_shift, d_ic), m_projectionType, m_shift); } } else { - return traverser_t(m_set.get_traverser_impl(_index >> m_shift, d_ic), m_projectionType, m_shift); + return traverser_t(m_set.get_traverser(_index >> m_shift, d_ic), m_projectionType, m_shift); } } - - private: + + private: Set m_set; - std::size_t m_level_impl; + std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; - }; -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index af8f29af4..b67d88e9d 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -15,23 +15,17 @@ namespace samurai //// Forward Declarations //////////////////////////////////////////////////////////////////////// - template - struct SelfTraits; - template struct SetTraits; template class SetBase; - template - concept Set_concept = std::is_base_of, T>::value; - template class Projection; - template - void apply(const Set& set, Func&& func); + template + void apply(const SetBase& set, Func&& func); //////////////////////////////////////////////////////////////////////// //// Class definition @@ -46,10 +40,10 @@ namespace samurai template using traverser_t = typename DerivedTraits::template traverser_t; - using interval_t = typename SetTraverserTraits>::interval_t; + using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; - static constexpr std::size_t dim = DerivedTraits::getDim(); + static constexpr std::size_t dim = DerivedTraits::dim; const Derived& derived_cast() const { @@ -61,23 +55,23 @@ namespace samurai return static_cast(*this); } - std::size_t level() const + inline std::size_t level() const { return derived_cast().level_impl(); } - bool exist() const + inline bool exist() const { return derived_cast().exist_impl(); } - bool empty() const + inline bool empty() const { return derived_cast().empty_impl(); } template - traverser_t get_traverser(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser(const index_t& index, std::integral_constant d_ic) const { return derived_cast().get_traverser_impl(index, d_ic); } @@ -103,16 +97,26 @@ namespace samurai } }; - template - struct SelfTraits { using Type = Set; }; + #define SAMURAI_SET_TYPEDEFS \ + using Base = SetBase; \ + \ + template \ + using traverser_t = typename Base::template traverser_t; \ + \ + using interval_t = typename Base::interval_t; \ + using value_t = typename Base::value_t; \ + + #define SAMURAI_SET_CONSTEXPRS \ + static constexpr std::size_t dim = Base::dim; \ - template - const Set& self(const Set& set) + template + struct IsSet : std::bool_constant< std::is_base_of, T>::value > {}; + + template + const Set& self(const SetBase& set) { - return set; + return set.derived_cast(); } - - } // namespace samurai diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 2c9f496b9..6e54b1542 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -6,68 +6,65 @@ #include "set_base.hpp" #include "traversers/translation_traverser.hpp" +#include +using namespace xt::placeholders; // this makes `_` available + namespace samurai { - template + template class Translation; - template + template struct SetTraits> { + static_assert(IsSet::value); + template using traverser_t = TranslationTraverser>; - - static constexpr std::size_t getDim() - { - return SetTraits::getDim(); - } + + static constexpr std::size_t dim = Set::dim; }; - template + template class Translation : public SetBase> { - using Self = Translation; - using Base = SetBase; - using SelfTraits = SetTraits; - - public: - - template - using traverser_t = typename Base::template traverser_t; - - using value_t = typename Base::value_t; - using translation_t = xt::xtensor_fixed>; - - template + using Self = Translation; + public: + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + using translation_t = xt::xtensor_fixed>; + + template Translation(const Set& set, const translation_expr_t& translation_expr) : m_set(set) , m_translation(translation_expr) { } - - std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_set.level_impl(); + return m_set.level(); } - bool exist_impl() const + inline bool exist_impl() const { - return m_set.exist_impl(); + return m_set.exist(); } - bool empty_impl() const + inline bool empty_impl() const { - return m_set.empty_impl(); + return m_set.empty(); } - + template - traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic), m_translation[d]); + return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic), m_translation[d]); } - - private: + + private: Set m_set; translation_t m_translation; @@ -79,4 +76,5 @@ namespace samurai return Translation(self(set), translation); } -} + +} // namespace samurai diff --git a/include/samurai/subset/traversers/box_traverser.hpp b/include/samurai/subset/traversers/box_traverser.hpp index fc4fe8b10..8e06764a8 100644 --- a/include/samurai/subset/traversers/box_traverser.hpp +++ b/include/samurai/subset/traversers/box_traverser.hpp @@ -1,64 +1,58 @@ // Copyright 2018-2025 the samurai's authors // SPDX-License-Identifier: BSD-3-Clause +#pragma once + +#include "set_traverser_base.hpp" #include "../../box.hpp" #include "../../interval.hpp" -#include "set_traverser_base.hpp" - -#pragma once +#include namespace samurai { - template - concept Box_concept = std::same_as, T>; - - template + template class BoxTraverser; - template + template struct SetTraverserTraits> { + static_assert(std::same_as, B>); + using interval_t = Interval; using current_interval_t = const interval_t&; }; - - template - class BoxTraverser : public SetTraverserBase> + + template + class BoxTraverser : public SetTraverserBase< BoxTraverser > { - using Self = BoxTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - - BoxTraverser(const value_t& start, const value_t& end) + using Self = BoxTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + BoxTraverser(const value_t& start, const value_t& end) : m_current_interval{start, end} , m_empty(false) { } - - inline bool is_empty() const + + inline bool is_empty_impl() const { - return m_empty; + return m_empty; } - inline void next_interval() + inline void next_interval_impl() { - assert(!is_empty()); - m_empty = true; + m_empty = true; } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - interval_t m_current_interval; + + private: + interval_t m_current_interval; bool m_empty; - }; -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/contraction_traverser.hpp b/include/samurai/subset/traversers/contraction_traverser.hpp index 577443462..d05e84cdb 100644 --- a/include/samurai/subset/traversers/contraction_traverser.hpp +++ b/include/samurai/subset/traversers/contraction_traverser.hpp @@ -3,66 +3,60 @@ #pragma once -#include "../utils.hpp" #include "set_traverser_base.hpp" namespace samurai { - template + template class ContractionTraverser; - template + template struct SetTraverserTraits> { - using interval_t = typename SetTraverserTraits::interval_t; + static_assert(IsSetTraverser::value); + + using interval_t = typename SetTraverser::interval_t; using current_interval_t = interval_t; }; - template + template class ContractionTraverser : public SetTraverserBase> { using Self = ContractionTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - - ContractionTraverser(const SetTraverser& set_traverser, const value_t contraction) + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + ContractionTraverser(const SetTraverser& set_traverser, const value_t contraction) : m_set_traverser(set_traverser) , m_contraction(contraction) { assert(m_contraction >= 0); } - - inline bool is_empty() const + + inline bool is_empty_impl() const { - return m_set_traverser.is_empty(); + return m_set_traverser.is_empty(); } - inline void next_interval() + inline void next_interval_impl() { - assert(!is_empty()); - m_set_traverser.next_interval(); + m_set_traverser.next_interval(); while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) { m_set_traverser.next_interval(); } } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { return current_interval_t(m_set_traverser.current_interval().start + m_contraction, m_set_traverser.current_interval().end - m_contraction); } - - private: + private: SetTraverser m_set_traverser; - value_t m_contraction; + value_t m_contraction; }; -} +} // namespace samurai diff --git a/include/samurai/subset/traversers/difference_id_traverser.hpp b/include/samurai/subset/traversers/difference_id_traverser.hpp index f074393b5..344531358 100644 --- a/include/samurai/subset/traversers/difference_id_traverser.hpp +++ b/include/samurai/subset/traversers/difference_id_traverser.hpp @@ -3,57 +3,54 @@ #pragma once -#include "../../static_algorithm.hpp" -#include "../utils.hpp" #include "set_traverser_base.hpp" namespace samurai { - template + template class DifferenceIdTraverser; - template + template struct SetTraverserTraits> { - using interval_t = typename SetTraverserTraits::interval_t; + static_assert(IsSetTraverser::value); + static_assert((IsSetTraverser::value and ...)); + + using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = interval_t; }; - template + template class DifferenceIdTraverser : public SetTraverserBase> { - using Self = DifferenceIdTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - - static constexpr std::size_t nIntervals = 1 + sizeof...(OtherSetTraversers); - - DifferenceIdTraverser(const std::array& shifts, + using Self = DifferenceIdTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + static constexpr std::size_t nIntervals = 1 + sizeof...(OtherSetTraversers); + + DifferenceIdTraverser(const std::array& shifts, const FirstSetTraverser& set_traverser, const OtherSetTraversers&...) : m_set_traverser(set_traverser) , m_shift(shifts[0]) { } + + DifferenceIdTraverser() = delete; - inline bool is_empty() const + inline bool is_empty_impl() const { return m_set_traverser.is_empty(); } - inline void next_interval() + inline void next_interval_impl() { - assert(!is_empty()); m_set_traverser.next_interval(); } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { return current_interval_t{m_set_traverser.current_interval().start << m_shift, m_set_traverser.current_interval().end << m_shift}; } @@ -64,4 +61,4 @@ namespace samurai std::size_t m_shift; }; -} +} // namespace samurai diff --git a/include/samurai/subset/traversers/difference_traverser.hpp b/include/samurai/subset/traversers/difference_traverser.hpp index 5d3da595e..e237f586a 100644 --- a/include/samurai/subset/traversers/difference_traverser.hpp +++ b/include/samurai/subset/traversers/difference_traverser.hpp @@ -3,42 +3,38 @@ #pragma once -#include "../../static_algorithm.hpp" -#include "../utils.hpp" #include "set_traverser_base.hpp" +#include "../../static_algorithm.hpp" namespace samurai { - - template + + template class DifferenceTraverser; - template + template struct SetTraverserTraits> { - using Childrens = std::tuple; - using interval_t = typename SetTraverserTraits>::interval_t; + static_assert((IsSetTraverser::value and ...)); + + using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; + using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = const interval_t&; }; - - template + + template class DifferenceTraverser : public SetTraverserBase> { - using Self = DifferenceTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - using Childrens = typename SetTraverserTraits::Childrens; + using Self = DifferenceTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + using Childrens = std::tuple; template using IthChild = std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; - + DifferenceTraverser(const std::array& shifts, const SetTraversers&... set_traversers) : m_min_start(std::numeric_limits::min()) , m_set_traversers(set_traversers...) @@ -46,27 +42,26 @@ namespace samurai { compute_current_interval(); } - - inline bool is_empty() const + + inline bool is_empty_impl() const { - return std::get<0>(m_set_traversers).is_empty(); + return std::get<0>(m_set_traversers).is_empty(); } - inline void next_interval() + inline void next_interval_impl() { - assert(!is_empty()); - advance_ref_interval(); - compute_current_interval(); + advance_ref_interval(); + compute_current_interval(); } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - inline void advance_ref_interval() + + private: + + inline void advance_ref_interval() { if (m_current_interval.end != std::get<0>(m_set_traversers).current_interval().end << m_shifts[0]) { @@ -81,7 +76,7 @@ namespace samurai std::get<0>(m_set_traversers).next_interval(); } } - + inline void compute_current_interval() { while (!std::get<0>(m_set_traversers).is_empty() && !try_to_compute_current_interval()) @@ -89,7 +84,7 @@ namespace samurai advance_ref_interval(); } } - + inline bool try_to_compute_current_interval() { assert(!std::get<0>(m_set_traversers).is_empty()); @@ -121,11 +116,11 @@ namespace samurai return m_current_interval.is_valid(); } - - interval_t m_current_interval; + + interval_t m_current_interval; value_t m_min_start; Childrens m_set_traversers; const std::array& m_shifts; - }; + }; -} +} // namespace samurai diff --git a/include/samurai/subset/traversers/intersection_traverser.hpp b/include/samurai/subset/traversers/intersection_traverser.hpp index 1e1997acd..d455ae653 100644 --- a/include/samurai/subset/traversers/intersection_traverser.hpp +++ b/include/samurai/subset/traversers/intersection_traverser.hpp @@ -3,51 +3,50 @@ #pragma once -#include "../utils.hpp" #include "set_traverser_base.hpp" namespace samurai { - template + template class IntersectionTraverser; - template + template struct SetTraverserTraits> { - using Childrens = std::tuple; - using interval_t = typename SetTraverserTraits>::interval_t; + static_assert((IsSetTraverser::value and ...)); + + using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; + using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = const interval_t&; }; - - template + + template class IntersectionTraverser : public SetTraverserBase> { - using Self = IntersectionTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - using Childrens = typename SetTraverserTraits::Childrens; + using Self = IntersectionTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + using Childrens = std::tuple; + + template + using IthChild = std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; - + IntersectionTraverser(const std::array& shifts, const SetTraversers&... set_traverser) : m_set_traversers(set_traverser...) , m_shifts(shifts) { - next_interval(); + next_interval_impl(); } - + inline bool is_empty_impl() const { - return !m_current_interval.is_valid(); + return !m_current_interval.is_valid(); } - inline void next_interval() + inline void next_interval_impl() { m_current_interval.start = 0; m_current_interval.end = 0; @@ -81,14 +80,14 @@ namespace samurai } } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - inline bool not_is_any_child_empty() const + + private: + + inline bool not_is_any_child_empty() const { return std::apply( [](const auto&... set_traversers) @@ -97,9 +96,10 @@ namespace samurai }, m_set_traversers); } - - interval_t m_current_interval; + + interval_t m_current_interval; Childrens m_set_traversers; const std::array& m_shifts; - }; -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/lca_batch_traverser.hpp b/include/samurai/subset/traversers/lca_batch_traverser.hpp deleted file mode 100644 index 03ee0640c..000000000 --- a/include/samurai/subset/traversers/lca_batch_traverser.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#include "../../level_cell_array.hpp" -#include "set_traverser_base.hpp" - -#pragma once - -namespace samurai -{ - template - class LCABatchTraverser; - - template - struct SetTraverserTraits> - { - using interval_t = typename LCA::interval_t; - using current_interval_t = const interval_t&; - }; - - template - class LCABatchTraverser : public SetTraverserBase> - { - using Self = LCABatchTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - using vector_interval_iterator = typename std::vector::const_iterator; - using list_interval_iterator = typename std::vector::const_iterator; - - LCABatchTraverser(const vector_interval_iterator first, const vector_interval_iterator end) - : m_vector_first_interval(first) - , m_vector_end_interval(end) - , m_use_vector_iterator(true) - { - } - - LCABatchTraverser(const list_interval_iterator first, const list_interval_iterator end) - : m_list_first_interval(first) - , m_list_end_interval(end) - , m_use_vector_iterator(false) - { - } - - inline bool is_empty_impl() const - { - return m_use_vector_iterator ? m_vector_first_interval == m_vector_end_interval : m_list_first_interval == m_list_end_interval; - } - - inline void next_interval_impl() - { - assert(!is_empty_impl()); - if (m_use_vector_iterator) - { - ++m_vector_first_interval; - } - else - { - ++m_list_first_interval; - } - } - - inline current_interval_t current_interval_impl() const - { - return m_use_vector_iterator ? *m_vector_first_interval : *m_list_first_interval; - } - - private: - - vector_interval_iterator m_vector_first_interval; - vector_interval_iterator m_vector_end_interval; - list_interval_iterator m_list_first_interval; - list_interval_iterator m_list_end_interval; - bool m_use_vector_iterator; - }; -} diff --git a/include/samurai/subset/traversers/lca_traverser.hpp b/include/samurai/subset/traversers/lca_traverser.hpp index d9a426c4a..f99bd1805 100644 --- a/include/samurai/subset/traversers/lca_traverser.hpp +++ b/include/samurai/subset/traversers/lca_traverser.hpp @@ -1,53 +1,47 @@ // Copyright 2018-2025 the samurai's authors // SPDX-License-Identifier: BSD-3-Clause -#include "../../level_cell_array.hpp" -#include "set_traverser_base.hpp" - #pragma once +#include "set_traverser_base.hpp" +#include + namespace samurai { - template - concept LCA_concept = std::same_as, T>; + template class LevelCellArray; - template - class LCATraverser; + template class LCATraverser; - template + template struct SetTraverserTraits> { + static_assert(std::same_as, LCA>); + using interval_t = typename LCA::interval_t; using current_interval_t = const interval_t&; }; - - template + + template class LCATraverser : public SetTraverserBase> { - using Self = LCATraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - using interval_iterator = typename std::vector::const_iterator; - - LCATraverser(const interval_iterator first, const interval_iterator end) + using Self = LCATraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + using interval_iterator = typename std::vector::const_iterator; + + LCATraverser(const interval_iterator first, const interval_iterator end) : m_first_interval(first) , m_end_interval(end) { } - - inline bool is_empty_impl() const + + inline bool is_empty_impl() const { return m_first_interval == m_end_interval; } inline void next_interval_impl() { - assert(!is_empty_impl()); ++m_first_interval; } @@ -55,10 +49,10 @@ namespace samurai { return *m_first_interval; } - + private: - interval_iterator m_first_interval; interval_iterator m_end_interval; - }; -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index fe952e846..2c8076746 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -3,44 +3,39 @@ #pragma once -#include "../../samurai_config.hpp" -#include "../fixed_capacity_array.hpp" #include "set_traverser_base.hpp" +#include "../fixed_capacity_array.hpp" #include namespace samurai { - - enum class ProjectionType + enum class ProjectionType { COARSEN, REFINE }; - template + template class ProjectionTraverser; - template - struct SetTraverserTraits> + template + struct SetTraverserTraits> { - using interval_t = typename SetTraverserTraits::interval_t; + static_assert(IsSetTraverser::value); + + using interval_t = typename SetTraverser::interval_t; using current_interval_t = const interval_t&; }; - template - class ProjectionTraverser : public SetTraverserBase> + template + class ProjectionTraverser : public SetTraverserBase> { - using Self = ProjectionTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - - ProjectionTraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) + using Self = ProjectionTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + ProjectionTraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) : m_projectionType(projectionType) , m_shift(shift) , m_isEmpty(set_traverser.is_empty()) @@ -70,26 +65,25 @@ namespace samurai } } } - + /* * This constructor only works for coarsening */ - ProjectionTraverser(const FixedCapacityArray& set_traversers, const std::size_t shift) + ProjectionTraverser(const FixedCapacityArray& set_traversers, const std::size_t shift) : m_set_traversers(set_traversers) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) { next_interval_coarsen(); } - - inline bool is_empty() const + + inline bool is_empty_impl() const { - return m_isEmpty; + return m_isEmpty; } - inline void next_interval() + inline void next_interval_impl() { - assert(!is_empty()); if (m_projectionType == ProjectionType::COARSEN) { next_interval_coarsen(); @@ -106,14 +100,14 @@ namespace samurai } } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - inline void next_interval_coarsen() + + private: + + inline void next_interval_coarsen() { m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift @@ -152,7 +146,7 @@ namespace samurai } m_isEmpty = (m_current_interval.start == std::numeric_limits::max()); } - + inline value_t coarsen_start(const interval_t& interval) const { return interval.start >> m_shift; @@ -163,13 +157,12 @@ namespace samurai const value_t trial_end = interval.end >> m_shift; return (trial_end << m_shift) < interval.end ? trial_end + 1 : trial_end; } - - //~ std::vector m_set_traversers; - FixedCapacityArray m_set_traversers; + + FixedCapacityArray m_set_traversers; ProjectionType m_projectionType; std::size_t m_shift; interval_t m_current_interval; bool m_isEmpty; - }; - -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/set_traverser_base.hpp b/include/samurai/subset/traversers/set_traverser_base.hpp index 22995cd9d..87eb645bc 100644 --- a/include/samurai/subset/traversers/set_traverser_base.hpp +++ b/include/samurai/subset/traversers/set_traverser_base.hpp @@ -1,12 +1,11 @@ // Copyright 2018-2025 the samurai's authors // SPDX-License-Identifier: BSD-3-Clause -#include +#pragma once +#include #include -#pragma once - namespace samurai { template @@ -15,9 +14,6 @@ namespace samurai template class SetTraverserBase; - template - concept SetTraverser_concept = std::is_base_of, T>::value; - template class SetTraverserBase { @@ -44,6 +40,7 @@ namespace samurai inline void next_interval() { + assert(!is_empty()); derived_cast().next_interval_impl(); } @@ -52,4 +49,14 @@ namespace samurai return derived_cast().current_interval_impl(); } }; -} + + template + struct IsSetTraverser : std::bool_constant< std::is_base_of, T>::value > {}; + + #define SAMURAI_SET_TRAVERSER_TYPEDEFS \ + using Base = SetTraverserBase; \ + using interval_t = typename Base::interval_t; \ + using current_interval_t = typename Base::current_interval_t; \ + using value_t = typename Base::value_t; \ + +} // namespace samurai diff --git a/include/samurai/subset/traversers/translation_traverser.hpp b/include/samurai/subset/traversers/translation_traverser.hpp index f4577d065..39d799cf7 100644 --- a/include/samurai/subset/traversers/translation_traverser.hpp +++ b/include/samurai/subset/traversers/translation_traverser.hpp @@ -1,61 +1,57 @@ // Copyright 2018-2025 the samurai's authors // SPDX-License-Identifier: BSD-3-Clause -#include "set_traverser_base.hpp" - #pragma once +#include "set_traverser_base.hpp" + namespace samurai { - template + template class TranslationTraverser; - template + template struct SetTraverserTraits> { + static_assert(IsSetTraverser::value); + using interval_t = typename SetTraverserTraits::interval_t; using current_interval_t = interval_t; }; - template + template class TranslationTraverser : public SetTraverserBase> { using Self = TranslationTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - - TranslationTraverser(const SetTraverser& set_traverser, const value_t& translation) + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + TranslationTraverser(const SetTraverser& set_traverser, const value_t& translation) : m_set_traverser(set_traverser) , m_translation(translation) { } - - inline bool is_empty() const + + inline bool is_empty_impl() const { - return m_set_traverser.is_empty(); + return m_set_traverser.is_empty(); } - inline void next_interval() + inline void next_interval_impl() { - assert(!is_empty()); - m_set_traverser.next_interval(); + m_set_traverser.next_interval(); } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { - return current_interval_t{m_set_traverser.current_interval().start + m_translation, + return current_interval_t{m_set_traverser.current_interval().start + m_translation, m_set_traverser.current_interval().end + m_translation}; } - - private: - + + private: SetTraverser m_set_traverser; value_t m_translation; - }; -} + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/union_traverser.hpp b/include/samurai/subset/traversers/union_traverser.hpp index 1af2ec968..365b1fb7e 100644 --- a/include/samurai/subset/traversers/union_traverser.hpp +++ b/include/samurai/subset/traversers/union_traverser.hpp @@ -8,47 +8,48 @@ namespace samurai { - template + template class UnionTraverser; - template + template struct SetTraverserTraits> { - using Childrens = std::tuple; - using interval_t = typename SetTraverserTraits>::interval_t; + static_assert((IsSetTraverser::value and ...)); + + using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; + using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = const interval_t&; }; - - template + + template class UnionTraverser : public SetTraverserBase> { - using Self = UnionTraverser; - using Base = SetTraverserBase; - - public: - - using interval_t = typename Base::interval_t; - using current_interval_t = typename Base::current_interval_t; - using value_t = typename Base::value_t; - using Childrens = typename SetTraverserTraits::Childrens; + using Self = UnionTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + using Childrens = std::tuple; + + template + using IthChild = std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; - - UnionTraverser(const std::array& shifts, const SetTraversers&... set_traversers) + + UnionTraverser(const std::array& shifts, const SetTraversers&... set_traversers) : m_set_traversers(set_traversers...) , m_shifts(shifts) { - next_interval(); + next_interval_impl(); } + - inline bool is_empty() const + inline bool is_empty_impl() const { - return m_current_interval.start == std::numeric_limits::max(); + return m_current_interval.start == std::numeric_limits::max(); } - inline void next_interval() + inline void next_interval_impl() { - m_current_interval.start = std::numeric_limits::max(); + m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start << m_shifts[i] enumerate_const_items( m_set_traversers, @@ -88,19 +89,18 @@ namespace samurai m_current_interval.end = set_traverser.current_interval().end << m_shifts[i]; } }); - } + } } - inline current_interval_t current_interval() const + inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: + private: interval_t m_current_interval; Childrens m_set_traversers; const std::array& m_shifts; - }; + }; -} +} // namespace samurai diff --git a/include/samurai/subset/utils.hpp b/include/samurai/subset/utils.hpp index 3b5c95456..a45c1e1bb 100644 --- a/include/samurai/subset/utils.hpp +++ b/include/samurai/subset/utils.hpp @@ -112,5 +112,4 @@ namespace samurai return detail::enumerate_const_items(tuple, func, std::make_index_sequence{}); } - //////////////////////////////////////////////////////////////////////// -} +} // namespace samurai diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index bb011b38f..43aa064b3 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -223,9 +223,10 @@ namespace samurai { EXPECT_EQ(interval_t(0, 20), i); }); - - EXPECT_EQ(set.on(5).level(), 5); - apply(set, + + auto set2 = set.on(5); + EXPECT_EQ(set2.level(), 5); + apply(set2, [](auto& i, auto) { EXPECT_EQ(interval_t(0, 40), i); From 66deefd8abd8bde1c7d792f33757643ce45a02d1 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 17 Sep 2025 15:09:40 +0200 Subject: [PATCH 03/28] with pre-commit --- include/samurai/algorithm.hpp | 2 +- include/samurai/level_cell_array.hpp | 20 +-- include/samurai/subset/box_view.hpp | 42 ++--- include/samurai/subset/contraction.hpp | 64 ++++---- .../samurai/subset/fixed_capacity_array.hpp | 147 ++++++++++++------ include/samurai/subset/lca_view.hpp | 63 ++++---- include/samurai/subset/nary_set_operator.hpp | 73 ++++----- include/samurai/subset/node.hpp | 4 +- include/samurai/subset/projection.hpp | 49 +++--- include/samurai/subset/set_base.hpp | 29 ++-- include/samurai/subset/translation.hpp | 47 +++--- .../subset/traversers/box_traverser.hpp | 43 ++--- .../traversers/contraction_traverser.hpp | 25 +-- .../traversers/difference_id_traverser.hpp | 26 ++-- .../traversers/difference_traverser.hpp | 54 +++---- .../traversers/intersection_traverser.hpp | 46 +++--- .../subset/traversers/lca_traverser.hpp | 37 +++-- .../traversers/projection_traverser.hpp | 46 +++--- .../subset/traversers/set_traverser_base.hpp | 24 +-- .../traversers/translation_traverser.hpp | 31 ++-- .../subset/traversers/union_traverser.hpp | 46 +++--- tests/test_subset.cpp | 4 +- 22 files changed, 508 insertions(+), 414 deletions(-) diff --git a/include/samurai/algorithm.hpp b/include/samurai/algorithm.hpp index 2d43ce269..9c262b4a4 100644 --- a/include/samurai/algorithm.hpp +++ b/include/samurai/algorithm.hpp @@ -133,7 +133,7 @@ namespace samurai //~ f(set.level(), i, index); //~ }); //~ } - + template inline void for_each_interval(const SetBase& set, Func&& f) { diff --git a/include/samurai/level_cell_array.hpp b/include/samurai/level_cell_array.hpp index 515d0d65d..df3214d1b 100644 --- a/include/samurai/level_cell_array.hpp +++ b/include/samurai/level_cell_array.hpp @@ -96,8 +96,8 @@ namespace samurai //~ template //~ LevelCellArray(Subset set); - - template + + template LevelCellArray(const SetBase& set); LevelCellArray(std::size_t level, const Box& box); @@ -358,19 +358,19 @@ namespace samurai //~ add_interval_back(i, index); //~ }); //~ } - - template - template + + template + template inline LevelCellArray::LevelCellArray(const SetBase& set) - : m_level(set.level()) - { - set( + : m_level(set.level()) + { + set( [this](const auto& i, const auto& index) { add_interval_back(i, index); }); - } - + } + //~ template //~ template //~ inline LevelCellArray::LevelCellArray(Subset set) diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 19347f8fa..fb87ee1e6 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -9,17 +9,17 @@ namespace samurai { - template + template class BoxView; template struct SetTraits> { - static_assert(std::same_as, B>); - + static_assert(std::same_as, B>); + template using traverser_t = BoxTraverser; - + static constexpr std::size_t dim = B::dim; }; @@ -27,46 +27,48 @@ namespace samurai class BoxView : public SetBase> { using Self = BoxView; - public: - SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS - - BoxView(const std::size_t level, const B& box) + + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + BoxView(const std::size_t level, const B& box) : m_level(level) , m_box(box) { } - + inline std::size_t level_impl() const { - return m_level; + return m_level; } inline bool exist_impl() const { - return m_box.is_valid(); + return m_box.is_valid(); } inline bool empty_impl() const { - return !exist_impl(); + return !exist_impl(); } - + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const { - if constexpr (d != dim - 1) + if constexpr (d != dim - 1) { assert(m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]); } - return traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]); + return traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]); } - - private: + + private: std::size_t m_level; const B& m_box; - }; - + }; + } // namespace samurai diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 1d33a017d..b33a8956d 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -9,17 +9,17 @@ namespace samurai { - template + template class Contraction; template struct SetTraits> { - static_assert(IsSet::value); - + static_assert(IsSet::value); + template using traverser_t = ContractionTraverser>; - + static constexpr std::size_t dim = Set::dim; }; @@ -27,12 +27,14 @@ namespace samurai class Contraction : public SetBase> { using Self = Contraction; - public: - SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS - using contraction_t = std::array; - using do_contraction_t = std::array; + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + using contraction_t = std::array; + using do_contraction_t = std::array; Contraction(const Set& set, const contraction_t& contraction) : m_set(set) @@ -52,43 +54,43 @@ namespace samurai assert(contraction >= 0); std::fill(m_contraction.begin(), m_contraction.end(), contraction); } - + Contraction(const Set& set, const value_t contraction, const do_contraction_t& do_contraction) - : m_set(set) + : m_set(set) { - for (std::size_t i=0; i!=m_contraction.size(); ++i) - { - m_contraction[i] = contraction*do_contraction[i]; - } - - } - + for (std::size_t i = 0; i != m_contraction.size(); ++i) + { + m_contraction[i] = contraction * do_contraction[i]; + } + } + inline std::size_t level_impl() const { - return m_set.level(); + return m_set.level(); } inline bool exist_impl() const { - return m_set.exist(); + return m_set.exist(); } inline bool empty_impl() const { - return m_set.empty(); + return m_set.empty(); } - + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return traverser_t(m_set.get_traverser(index, d_ic), m_contraction[d]); + return traverser_t(m_set.get_traverser(index, d_ic), m_contraction[d]); } - - private: + + private: + Set m_set; contraction_t m_contraction; - }; - + }; + template auto contract(const Set& sets, const typename Contraction>::contraction_t& contraction) { @@ -102,9 +104,13 @@ namespace samurai } template - auto contract(const Set& sets, const typename Contraction>::value_t contraction, const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this more readable, perhaps a traits... + auto contract(const Set& sets, + const typename Contraction>::value_t contraction, + const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this + // more readable, + // perhaps a traits... { return Contraction(self(sets), contraction, do_contraction); } - + } // namespace samurai diff --git a/include/samurai/subset/fixed_capacity_array.hpp b/include/samurai/subset/fixed_capacity_array.hpp index 01ec6210b..48ee6bed4 100644 --- a/include/samurai/subset/fixed_capacity_array.hpp +++ b/include/samurai/subset/fixed_capacity_array.hpp @@ -6,39 +6,48 @@ #include #include -template +template class FixedCapacityArray { - using CoreElement = std::conditional_t< std::is_trivially_constructible::value, T, std::aligned_storage_t >; -public: - FixedCapacityArray() noexcept : m_end(begin()) {} + using CoreElement = std::conditional_t::value, T, std::aligned_storage_t>; - FixedCapacityArray(const std::size_t size, const T& value = T()) requires(std::is_trivially_constructible::value) - { + public: + + FixedCapacityArray() noexcept + : m_end(begin()) + { + } + + FixedCapacityArray(const std::size_t size, const T& value = T()) + requires(std::is_trivially_constructible::value) + { assert(size <= N); m_end = begin() + size; - for (T* it = begin(); it!=end(); ++it) + for (T* it = begin(); it != end(); ++it) { std::construct_at(it, value); } } FixedCapacityArray(const FixedCapacityArray& other) - { + { copyFrom(std::cbegin(other), std::cend(other)); } FixedCapacityArray(FixedCapacityArray&& other) noexcept - { + { moveFrom(std::cbegin(other), std::cend(other)); other.clear(); } - ~FixedCapacityArray() { clear(); } + ~FixedCapacityArray() + { + clear(); + } FixedCapacityArray& operator=(const FixedCapacityArray& other) { - if (this != std::addressof(other)) + if (this != std::addressof(other)) { clear(); copyFrom(std::cbegin(other), std::cend(other), begin()); @@ -48,7 +57,7 @@ class FixedCapacityArray FixedCapacityArray& operator=(FixedCapacityArray&& other) noexcept { - if (this != std::addressof(other)) + if (this != std::addressof(other)) { clear(); moveFrom(std::cbegin(other), std::cend(other), begin()); @@ -58,56 +67,97 @@ class FixedCapacityArray } T* begin() noexcept - { - if constexpr (std::is_trivially_constructible::value) { return m_core.data(); } - else { return reinterpret_cast(m_core.data()); } + { + if constexpr (std::is_trivially_constructible::value) + { + return m_core.data(); + } + else + { + return reinterpret_cast(m_core.data()); + } + } + + T* end() + { + return m_end; } - T* end() { return m_end; } const T* begin() const noexcept { - if constexpr (std::is_trivially_constructible::value) { return m_core.data(); } - else { return reinterpret_cast(m_core.data()); } + if constexpr (std::is_trivially_constructible::value) + { + return m_core.data(); + } + else + { + return reinterpret_cast(m_core.data()); + } } - const T* end() const { return m_end; } - - const T& operator[](const std::size_t i) const { return *(begin() + i); } - T& operator[](const std::size_t i) { return *(begin() + i); } + const T* end() const + { + return m_end; + } + + const T& operator[](const std::size_t i) const + { + return *(begin() + i); + } - std::ptrdiff_t ssize() const { return std::distance(begin(), end()); } - std::size_t size() const { return std::size_t(ssize()); } + T& operator[](const std::size_t i) + { + return *(begin() + i); + } - constexpr std::size_t capacity() const { return N; } + std::ptrdiff_t ssize() const + { + return std::distance(begin(), end()); + } - template - void emplace_back(Args&&... args) - { - assert(size() < N); - std::construct_at(m_end, std::forward(args)...); - ++m_end; + std::size_t size() const + { + return std::size_t(ssize()); } - void push_back(const T& value) { emplace_back(value); } + constexpr std::size_t capacity() const + { + return N; + } - void pop_back() - { - if (begin() != m_end) - { - --m_end; - std::destroy_at(m_end); - } + template + void emplace_back(Args&&... args) + { + assert(size() < N); + std::construct_at(m_end, std::forward(args)...); + ++m_end; } - void clear() - { - if constexpr (not std::is_trivially_destructible_v) + void push_back(const T& value) + { + emplace_back(value); + } + + void pop_back() + { + if (begin() != m_end) { - std::destroy(begin(), end()); + --m_end; + std::destroy_at(m_end); } - m_end = begin(); } -private: + + void clear() + { + if constexpr (not std::is_trivially_destructible_v) + { + std::destroy(begin(), end()); + } + m_end = begin(); + } + + private: + void copyFrom(const T* srcBegin, const T* srcEnd) { if constexpr (std::is_trivially_copyable::value) @@ -118,11 +168,10 @@ class FixedCapacityArray else { m_end = begin(); - for (const T* srcIt = srcBegin; srcIt!=srcEnd; ++srcIt, ++m_end) + for (const T* srcIt = srcBegin; srcIt != srcEnd; ++srcIt, ++m_end) { std::construct_at(m_end, *srcIt); } - } } @@ -136,7 +185,7 @@ class FixedCapacityArray else { m_end = begin(); - for (const T* srcIt = srcBegin; srcIt!=srcEnd; ++srcIt, ++m_end) + for (const T* srcIt = srcBegin; srcIt != srcEnd; ++srcIt, ++m_end) { std::construct_at(m_end, std::move(*srcIt)); } @@ -144,5 +193,5 @@ class FixedCapacityArray } std::array m_core; - T* m_end; + T* m_end; }; diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index b2bf72f98..c8b15a6b1 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -9,17 +9,17 @@ namespace samurai { - template + template class LCAView; template struct SetTraits> { - static_assert(std::same_as, LCA>); - + static_assert(std::same_as, LCA>); + template using traverser_t = LCATraverser; - + static constexpr std::size_t dim = LCA::dim; }; @@ -27,31 +27,36 @@ namespace samurai class LCAView : public SetBase> { using Self = LCAView; - public: - SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS - - LCAView(const LCA& lca) : m_lca(lca) {} - - inline std::size_t level_impl() const + + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + LCAView(const LCA& lca) + : m_lca(lca) + { + } + + inline std::size_t level_impl() const { - return m_lca.level(); + return m_lca.level(); } inline bool exist_impl() const { - return !empty_impl(); + return !empty_impl(); } inline bool empty_impl() const { - return m_lca.empty(); + return m_lca.empty(); } - + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const { - if constexpr (d != dim - 1) + if constexpr (d != dim - 1) { const auto& y = index[d]; const auto& y_intervals = m_lca[d + 1]; @@ -66,7 +71,7 @@ namespace samurai if (y_interval_it != y_intervals.cend()) { const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); - + return traverser_t(m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]), m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1])); } @@ -80,16 +85,16 @@ namespace samurai return traverser_t(m_lca[d].cbegin(), m_lca[d].cend()); } } - - private: - const LCA& m_lca; - }; - - - template - LCAView> self(const LevelCellArray& lca) - { - return LCAView>(lca); - } - + + private: + + const LCA& m_lca; + }; + + template + LCAView> self(const LevelCellArray& lca) + { + return LCAView>(lca); + } + } // namespace samurai diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 987eaaba2..ba8011a4c 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -18,58 +18,60 @@ namespace samurai INTERSECTION, DIFFERENCE }; - + template class NArySetOperator; template struct SetTraits> { - static_assert((IsSet::value and ...)); + static_assert((IsSet::value and ...)); - template + template using traverser_t = UnionTraverser...>; - + static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; }; template struct SetTraits> { - static_assert((IsSet::value and ...)); - - template + static_assert((IsSet::value and ...)); + + template using traverser_t = IntersectionTraverser...>; - + static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; }; template struct SetTraits> { - static_assert((IsSet::value and ...)); - - template + static_assert((IsSet::value and ...)); + + template using traverser_t = std::conditional_t...>, DifferenceIdTraverser...>>; - + static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; }; - + template class NArySetOperator : public SetBase> { - using Self = NArySetOperator; - public: - SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS - - using Childrens = std::tuple; - - static constexpr std::size_t nIntervals = std::tuple_size_v; - - explicit NArySetOperator(const Sets&... sets) + using Self = NArySetOperator; + + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + using Childrens = std::tuple; + + static constexpr std::size_t nIntervals = std::tuple_size_v; + + explicit NArySetOperator(const Sets&... sets) : m_sets(sets...) { m_level = std::apply( @@ -85,15 +87,15 @@ namespace samurai m_shifts[i] = std::size_t(m_level - set.level()); }); } - - inline std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_level; + return m_level; } inline bool exist_impl() const { - return std::apply( + return std::apply( [](const auto first_set, const auto&... other_sets) -> std::size_t { if constexpr (op == SetOperator::UNION) @@ -132,17 +134,18 @@ namespace samurai }, m_sets); } - + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return get_traverser_impl_impl(index, d_ic, std::make_index_sequence{}); + return get_traverser_impl_impl(index, d_ic, std::make_index_sequence{}); } - - private: + + private: template - traverser_t get_traverser_impl_impl(const index_t& index, std::integral_constant d_ic, std::index_sequence) const + traverser_t + get_traverser_impl_impl(const index_t& index, std::integral_constant d_ic, std::index_sequence) const { return traverser_t(m_shifts, std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic)...); } @@ -150,8 +153,8 @@ namespace samurai Childrens m_sets; std::size_t m_level; std::array m_shifts; - }; - + }; + //////////////////////////////////////////////////////////////////////// //// functions //////////////////////////////////////////////////////////////////////// @@ -182,5 +185,5 @@ namespace samurai return Difference(self(sets)...); } - + } // namespace samurai diff --git a/include/samurai/subset/node.hpp b/include/samurai/subset/node.hpp index 43771ffd1..e397e33bc 100644 --- a/include/samurai/subset/node.hpp +++ b/include/samurai/subset/node.hpp @@ -3,12 +3,12 @@ #pragma once -#include "set_base.hpp" -#include "projection.hpp" #include "apply.hpp" #include "box_view.hpp" #include "contraction.hpp" #include "lca_view.hpp" #include "nary_set_operator.hpp" +#include "projection.hpp" +#include "set_base.hpp" #include "translation.hpp" #include "utils.hpp" diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index d196d298f..d23bfe75e 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -9,21 +9,20 @@ namespace samurai { - - template + template class Projection; template struct SetTraits> { - static_assert(IsSet::value); - + static_assert(IsSet::value); + template - using traverser_t = std::conditional_t, 1>, - ProjectionTraverser, default_config::max_level>>; - + ProjectionTraverser, default_config::max_level>>; + static constexpr std::size_t dim = Set::dim; }; @@ -31,11 +30,13 @@ namespace samurai class Projection : public SetBase> { using Self = Projection; - public: - SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS - - Projection(const Set& set, const std::size_t level) + + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + Projection(const Set& set, const std::size_t level) : m_set(set) , m_level(level) { @@ -50,38 +51,38 @@ namespace samurai m_shift = m_level - m_set.level(); } } - + inline std::size_t level_impl() const { - return m_level; + return m_level; } inline bool exist_impl() const { - return m_set.exist(); + return m_set.exist(); } inline bool empty_impl() const { - return m_set.empty(); + return m_set.empty(); } - + template inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const { - if (m_projectionType == ProjectionType::COARSEN) + if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != dim - 1) { const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; - + xt::xtensor_fixed> index(_index << m_shift); - + //~ std::vector> set_traversers; //~ set_traversers.reserve(size_t(ymax - ymin)); FixedCapacityArray, default_config::max_level> set_traversers; - + for (index[d] = ymin; index[d] != ymax; ++index[d]) { set_traversers.push_back(m_set.get_traverser(index, d_ic)); @@ -98,13 +99,13 @@ namespace samurai return traverser_t(m_set.get_traverser(_index >> m_shift, d_ic), m_projectionType, m_shift); } } - - private: + + private: Set m_set; std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; - }; + }; } // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index b67d88e9d..352424f75 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -97,20 +97,21 @@ namespace samurai } }; - #define SAMURAI_SET_TYPEDEFS \ - using Base = SetBase; \ - \ - template \ - using traverser_t = typename Base::template traverser_t; \ - \ - using interval_t = typename Base::interval_t; \ - using value_t = typename Base::value_t; \ - - #define SAMURAI_SET_CONSTEXPRS \ - static constexpr std::size_t dim = Base::dim; \ - - template - struct IsSet : std::bool_constant< std::is_base_of, T>::value > {}; +#define SAMURAI_SET_TYPEDEFS \ + using Base = SetBase; \ + \ + template \ + using traverser_t = typename Base::template traverser_t; \ + \ + using interval_t = typename Base::interval_t; \ + using value_t = typename Base::value_t; + +#define SAMURAI_SET_CONSTEXPRS static constexpr std::size_t dim = Base::dim; + + template + struct IsSet : std::bool_constant, T>::value> + { + }; template const Set& self(const SetBase& set) diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 6e54b1542..8b7722837 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -6,23 +6,23 @@ #include "set_base.hpp" #include "traversers/translation_traverser.hpp" -#include -using namespace xt::placeholders; // this makes `_` available +#include +using namespace xt::placeholders; // this makes `_` available namespace samurai { - template + template class Translation; template struct SetTraits> { - static_assert(IsSet::value); - + static_assert(IsSet::value); + template using traverser_t = TranslationTraverser>; - + static constexpr std::size_t dim = Set::dim; }; @@ -30,41 +30,43 @@ namespace samurai class Translation : public SetBase> { using Self = Translation; - public: - SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS - - using translation_t = xt::xtensor_fixed>; - - template + + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + using translation_t = xt::xtensor_fixed>; + + template Translation(const Set& set, const translation_expr_t& translation_expr) : m_set(set) , m_translation(translation_expr) { } - - inline std::size_t level_impl() const + + inline std::size_t level_impl() const { - return m_set.level(); + return m_set.level(); } inline bool exist_impl() const { - return m_set.exist(); + return m_set.exist(); } inline bool empty_impl() const { - return m_set.empty(); + return m_set.empty(); } - + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic), m_translation[d]); + return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic), m_translation[d]); } - - private: + + private: Set m_set; translation_t m_translation; @@ -76,5 +78,4 @@ namespace samurai return Translation(self(set), translation); } - } // namespace samurai diff --git a/include/samurai/subset/traversers/box_traverser.hpp b/include/samurai/subset/traversers/box_traverser.hpp index 8e06764a8..6ca2bc451 100644 --- a/include/samurai/subset/traversers/box_traverser.hpp +++ b/include/samurai/subset/traversers/box_traverser.hpp @@ -3,56 +3,59 @@ #pragma once -#include "set_traverser_base.hpp" #include "../../box.hpp" #include "../../interval.hpp" +#include "set_traverser_base.hpp" #include namespace samurai { - template + template class BoxTraverser; template struct SetTraverserTraits> { - static_assert(std::same_as, B>); - + static_assert(std::same_as, B>); + using interval_t = Interval; using current_interval_t = const interval_t&; }; - - template - class BoxTraverser : public SetTraverserBase< BoxTraverser > + + template + class BoxTraverser : public SetTraverserBase> { - using Self = BoxTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - BoxTraverser(const value_t& start, const value_t& end) + using Self = BoxTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + BoxTraverser(const value_t& start, const value_t& end) : m_current_interval{start, end} , m_empty(false) { } - + inline bool is_empty_impl() const { - return m_empty; + return m_empty; } inline void next_interval_impl() { - m_empty = true; + m_empty = true; } inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - interval_t m_current_interval; + + private: + + interval_t m_current_interval; bool m_empty; - }; + }; } // namespace samurai diff --git a/include/samurai/subset/traversers/contraction_traverser.hpp b/include/samurai/subset/traversers/contraction_traverser.hpp index d05e84cdb..a6e3314e2 100644 --- a/include/samurai/subset/traversers/contraction_traverser.hpp +++ b/include/samurai/subset/traversers/contraction_traverser.hpp @@ -14,8 +14,8 @@ namespace samurai template struct SetTraverserTraits> { - static_assert(IsSetTraverser::value); - + static_assert(IsSetTraverser::value); + using interval_t = typename SetTraverser::interval_t; using current_interval_t = interval_t; }; @@ -24,24 +24,26 @@ namespace samurai class ContractionTraverser : public SetTraverserBase> { using Self = ContractionTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - ContractionTraverser(const SetTraverser& set_traverser, const value_t contraction) + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + ContractionTraverser(const SetTraverser& set_traverser, const value_t contraction) : m_set_traverser(set_traverser) , m_contraction(contraction) { assert(m_contraction >= 0); } - + inline bool is_empty_impl() const { - return m_set_traverser.is_empty(); + return m_set_traverser.is_empty(); } inline void next_interval_impl() { - m_set_traverser.next_interval(); + m_set_traverser.next_interval(); while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) { m_set_traverser.next_interval(); @@ -53,10 +55,11 @@ namespace samurai return current_interval_t(m_set_traverser.current_interval().start + m_contraction, m_set_traverser.current_interval().end - m_contraction); } - private: + + private: SetTraverser m_set_traverser; - value_t m_contraction; + value_t m_contraction; }; } // namespace samurai diff --git a/include/samurai/subset/traversers/difference_id_traverser.hpp b/include/samurai/subset/traversers/difference_id_traverser.hpp index 344531358..af2f9b294 100644 --- a/include/samurai/subset/traversers/difference_id_traverser.hpp +++ b/include/samurai/subset/traversers/difference_id_traverser.hpp @@ -11,12 +11,12 @@ namespace samurai template class DifferenceIdTraverser; - template + template struct SetTraverserTraits> { - static_assert(IsSetTraverser::value); - static_assert((IsSetTraverser::value and ...)); - + static_assert(IsSetTraverser::value); + static_assert((IsSetTraverser::value and ...)); + using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = interval_t; }; @@ -24,20 +24,22 @@ namespace samurai template class DifferenceIdTraverser : public SetTraverserBase> { - using Self = DifferenceIdTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - static constexpr std::size_t nIntervals = 1 + sizeof...(OtherSetTraversers); - - DifferenceIdTraverser(const std::array& shifts, + using Self = DifferenceIdTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + static constexpr std::size_t nIntervals = 1 + sizeof...(OtherSetTraversers); + + DifferenceIdTraverser(const std::array& shifts, const FirstSetTraverser& set_traverser, const OtherSetTraversers&...) : m_set_traverser(set_traverser) , m_shift(shifts[0]) { } - + DifferenceIdTraverser() = delete; inline bool is_empty_impl() const diff --git a/include/samurai/subset/traversers/difference_traverser.hpp b/include/samurai/subset/traversers/difference_traverser.hpp index e237f586a..6f3c7bdd3 100644 --- a/include/samurai/subset/traversers/difference_traverser.hpp +++ b/include/samurai/subset/traversers/difference_traverser.hpp @@ -3,38 +3,40 @@ #pragma once -#include "set_traverser_base.hpp" #include "../../static_algorithm.hpp" +#include "set_traverser_base.hpp" namespace samurai { - + template class DifferenceTraverser; - template + template struct SetTraverserTraits> { - static_assert((IsSetTraverser::value and ...)); - - using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; + static_assert((IsSetTraverser::value and ...)); + + using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = const interval_t&; }; - + template class DifferenceTraverser : public SetTraverserBase> { - using Self = DifferenceTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - using Childrens = std::tuple; + using Self = DifferenceTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + using Childrens = std::tuple; template using IthChild = std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; - + DifferenceTraverser(const std::array& shifts, const SetTraversers&... set_traversers) : m_min_start(std::numeric_limits::min()) , m_set_traversers(set_traversers...) @@ -42,26 +44,26 @@ namespace samurai { compute_current_interval(); } - + inline bool is_empty_impl() const { - return std::get<0>(m_set_traversers).is_empty(); + return std::get<0>(m_set_traversers).is_empty(); } inline void next_interval_impl() { - advance_ref_interval(); - compute_current_interval(); + advance_ref_interval(); + compute_current_interval(); } inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - inline void advance_ref_interval() + + private: + + inline void advance_ref_interval() { if (m_current_interval.end != std::get<0>(m_set_traversers).current_interval().end << m_shifts[0]) { @@ -76,7 +78,7 @@ namespace samurai std::get<0>(m_set_traversers).next_interval(); } } - + inline void compute_current_interval() { while (!std::get<0>(m_set_traversers).is_empty() && !try_to_compute_current_interval()) @@ -84,7 +86,7 @@ namespace samurai advance_ref_interval(); } } - + inline bool try_to_compute_current_interval() { assert(!std::get<0>(m_set_traversers).is_empty()); @@ -116,11 +118,11 @@ namespace samurai return m_current_interval.is_valid(); } - - interval_t m_current_interval; + + interval_t m_current_interval; value_t m_min_start; Childrens m_set_traversers; const std::array& m_shifts; - }; + }; } // namespace samurai diff --git a/include/samurai/subset/traversers/intersection_traverser.hpp b/include/samurai/subset/traversers/intersection_traverser.hpp index d455ae653..54c9a3089 100644 --- a/include/samurai/subset/traversers/intersection_traverser.hpp +++ b/include/samurai/subset/traversers/intersection_traverser.hpp @@ -11,39 +11,41 @@ namespace samurai template class IntersectionTraverser; - template + template struct SetTraverserTraits> { - static_assert((IsSetTraverser::value and ...)); - - using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; + static_assert((IsSetTraverser::value and ...)); + + using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = const interval_t&; }; - + template class IntersectionTraverser : public SetTraverserBase> { - using Self = IntersectionTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - using Childrens = std::tuple; - - template + using Self = IntersectionTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + using Childrens = std::tuple; + + template using IthChild = std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; - + IntersectionTraverser(const std::array& shifts, const SetTraversers&... set_traverser) : m_set_traversers(set_traverser...) , m_shifts(shifts) { next_interval_impl(); } - + inline bool is_empty_impl() const { - return !m_current_interval.is_valid(); + return !m_current_interval.is_valid(); } inline void next_interval_impl() @@ -82,12 +84,12 @@ namespace samurai inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - inline bool not_is_any_child_empty() const + + private: + + inline bool not_is_any_child_empty() const { return std::apply( [](const auto&... set_traversers) @@ -96,10 +98,10 @@ namespace samurai }, m_set_traversers); } - - interval_t m_current_interval; + + interval_t m_current_interval; Childrens m_set_traversers; const std::array& m_shifts; - }; + }; } // namespace samurai diff --git a/include/samurai/subset/traversers/lca_traverser.hpp b/include/samurai/subset/traversers/lca_traverser.hpp index f99bd1805..acf33a962 100644 --- a/include/samurai/subset/traversers/lca_traverser.hpp +++ b/include/samurai/subset/traversers/lca_traverser.hpp @@ -8,34 +8,38 @@ namespace samurai { - template class LevelCellArray; + template + class LevelCellArray; - template class LCATraverser; + template + class LCATraverser; - template + template struct SetTraverserTraits> { - static_assert(std::same_as, LCA>); - + static_assert(std::same_as, LCA>); + using interval_t = typename LCA::interval_t; using current_interval_t = const interval_t&; }; - + template class LCATraverser : public SetTraverserBase> { - using Self = LCATraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - using interval_iterator = typename std::vector::const_iterator; - - LCATraverser(const interval_iterator first, const interval_iterator end) + using Self = LCATraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + using interval_iterator = typename std::vector::const_iterator; + + LCATraverser(const interval_iterator first, const interval_iterator end) : m_first_interval(first) , m_end_interval(end) { } - - inline bool is_empty_impl() const + + inline bool is_empty_impl() const { return m_first_interval == m_end_interval; } @@ -49,10 +53,11 @@ namespace samurai { return *m_first_interval; } - + private: + interval_iterator m_first_interval; interval_iterator m_end_interval; - }; + }; } // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 2c8076746..20c8063d9 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -3,14 +3,14 @@ #pragma once -#include "set_traverser_base.hpp" #include "../fixed_capacity_array.hpp" +#include "set_traverser_base.hpp" #include namespace samurai { - enum class ProjectionType + enum class ProjectionType { COARSEN, REFINE @@ -22,8 +22,8 @@ namespace samurai template struct SetTraverserTraits> { - static_assert(IsSetTraverser::value); - + static_assert(IsSetTraverser::value); + using interval_t = typename SetTraverser::interval_t; using current_interval_t = const interval_t&; }; @@ -31,11 +31,13 @@ namespace samurai template class ProjectionTraverser : public SetTraverserBase> { - using Self = ProjectionTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - ProjectionTraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) + using Self = ProjectionTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + ProjectionTraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) : m_projectionType(projectionType) , m_shift(shift) , m_isEmpty(set_traverser.is_empty()) @@ -65,7 +67,7 @@ namespace samurai } } } - + /* * This constructor only works for coarsening */ @@ -76,10 +78,10 @@ namespace samurai { next_interval_coarsen(); } - + inline bool is_empty_impl() const { - return m_isEmpty; + return m_isEmpty; } inline void next_interval_impl() @@ -102,12 +104,12 @@ namespace samurai inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - - private: - - inline void next_interval_coarsen() + + private: + + inline void next_interval_coarsen() { m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift @@ -146,7 +148,7 @@ namespace samurai } m_isEmpty = (m_current_interval.start == std::numeric_limits::max()); } - + inline value_t coarsen_start(const interval_t& interval) const { return interval.start >> m_shift; @@ -157,12 +159,12 @@ namespace samurai const value_t trial_end = interval.end >> m_shift; return (trial_end << m_shift) < interval.end ? trial_end + 1 : trial_end; } - - FixedCapacityArray m_set_traversers; + + FixedCapacityArray m_set_traversers; ProjectionType m_projectionType; std::size_t m_shift; interval_t m_current_interval; bool m_isEmpty; - }; - + }; + } // namespace samurai diff --git a/include/samurai/subset/traversers/set_traverser_base.hpp b/include/samurai/subset/traversers/set_traverser_base.hpp index 87eb645bc..196ffce61 100644 --- a/include/samurai/subset/traversers/set_traverser_base.hpp +++ b/include/samurai/subset/traversers/set_traverser_base.hpp @@ -40,7 +40,7 @@ namespace samurai inline void next_interval() { - assert(!is_empty()); + assert(!is_empty()); derived_cast().next_interval_impl(); } @@ -49,14 +49,16 @@ namespace samurai return derived_cast().current_interval_impl(); } }; - - template - struct IsSetTraverser : std::bool_constant< std::is_base_of, T>::value > {}; - - #define SAMURAI_SET_TRAVERSER_TYPEDEFS \ - using Base = SetTraverserBase; \ - using interval_t = typename Base::interval_t; \ - using current_interval_t = typename Base::current_interval_t; \ - using value_t = typename Base::value_t; \ - + + template + struct IsSetTraverser : std::bool_constant, T>::value> + { + }; + +#define SAMURAI_SET_TRAVERSER_TYPEDEFS \ + using Base = SetTraverserBase; \ + using interval_t = typename Base::interval_t; \ + using current_interval_t = typename Base::current_interval_t; \ + using value_t = typename Base::value_t; + } // namespace samurai diff --git a/include/samurai/subset/traversers/translation_traverser.hpp b/include/samurai/subset/traversers/translation_traverser.hpp index 39d799cf7..3f7b6cbb4 100644 --- a/include/samurai/subset/traversers/translation_traverser.hpp +++ b/include/samurai/subset/traversers/translation_traverser.hpp @@ -14,8 +14,8 @@ namespace samurai template struct SetTraverserTraits> { - static_assert(IsSetTraverser::value); - + static_assert(IsSetTraverser::value); + using interval_t = typename SetTraverserTraits::interval_t; using current_interval_t = interval_t; }; @@ -24,34 +24,37 @@ namespace samurai class TranslationTraverser : public SetTraverserBase> { using Self = TranslationTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - TranslationTraverser(const SetTraverser& set_traverser, const value_t& translation) + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + TranslationTraverser(const SetTraverser& set_traverser, const value_t& translation) : m_set_traverser(set_traverser) , m_translation(translation) { } - + inline bool is_empty_impl() const { - return m_set_traverser.is_empty(); + return m_set_traverser.is_empty(); } inline void next_interval_impl() { - m_set_traverser.next_interval(); + m_set_traverser.next_interval(); } inline current_interval_t current_interval_impl() const { - return current_interval_t{m_set_traverser.current_interval().start + m_translation, + return current_interval_t{m_set_traverser.current_interval().start + m_translation, m_set_traverser.current_interval().end + m_translation}; } - - private: + + private: + SetTraverser m_set_traverser; value_t m_translation; - }; - + }; + } // namespace samurai diff --git a/include/samurai/subset/traversers/union_traverser.hpp b/include/samurai/subset/traversers/union_traverser.hpp index 365b1fb7e..14b210d97 100644 --- a/include/samurai/subset/traversers/union_traverser.hpp +++ b/include/samurai/subset/traversers/union_traverser.hpp @@ -11,45 +11,46 @@ namespace samurai template class UnionTraverser; - template + template struct SetTraverserTraits> { - static_assert((IsSetTraverser::value and ...)); - - using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; + static_assert((IsSetTraverser::value and ...)); + + using FirstSetTraverser = std::tuple_element_t<0, std::tuple>; using interval_t = typename FirstSetTraverser::interval_t; using current_interval_t = const interval_t&; }; - + template class UnionTraverser : public SetTraverserBase> { - using Self = UnionTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - using Childrens = std::tuple; - - template + using Self = UnionTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + using Childrens = std::tuple; + + template using IthChild = std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; - - UnionTraverser(const std::array& shifts, const SetTraversers&... set_traversers) + + UnionTraverser(const std::array& shifts, const SetTraversers&... set_traversers) : m_set_traversers(set_traversers...) , m_shifts(shifts) { next_interval_impl(); } - - inline bool is_empty_impl() const + inline bool is_empty_impl() const { - return m_current_interval.start == std::numeric_limits::max(); + return m_current_interval.start == std::numeric_limits::max(); } inline void next_interval_impl() { - m_current_interval.start = std::numeric_limits::max(); + m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start << m_shifts[i] enumerate_const_items( m_set_traversers, @@ -89,18 +90,19 @@ namespace samurai m_current_interval.end = set_traverser.current_interval().end << m_shifts[i]; } }); - } + } } inline current_interval_t current_interval_impl() const { - return m_current_interval; + return m_current_interval; } - private: + + private: interval_t m_current_interval; Childrens m_set_traversers; const std::array& m_shifts; - }; + }; -} // namespace samurai +} // namespace samurai diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 43aa064b3..e9b152dff 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -223,8 +223,8 @@ namespace samurai { EXPECT_EQ(interval_t(0, 20), i); }); - - auto set2 = set.on(5); + + auto set2 = set.on(5); EXPECT_EQ(set2.level(), 5); apply(set2, [](auto& i, auto) From 5bcc53ab145daea6d72b9f5fb22f52bde3582097 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Mon, 29 Sep 2025 14:54:34 +0200 Subject: [PATCH 04/28] expand --- .../linear_convection_obstacle.cpp | 3 +- include/samurai/algorithm/update.hpp | 20 +++ include/samurai/level_cell_array.hpp | 17 ++ include/samurai/subset/box_view.hpp | 9 +- include/samurai/subset/contraction.hpp | 16 +- include/samurai/subset/expansion.hpp | 164 ++++++++++++++++++ include/samurai/subset/lca_view.hpp | 46 +++-- include/samurai/subset/nary_set_operator.hpp | 50 ++++-- include/samurai/subset/node.hpp | 1 + include/samurai/subset/projection.hpp | 44 +++-- include/samurai/subset/set_base.hpp | 13 ++ include/samurai/subset/translation.hpp | 4 +- .../subset/traversers/box_traverser.hpp | 2 +- .../subset/traversers/expansion_traverser.hpp | 97 +++++++++++ .../last_dim_expansion_traverser.hpp | 73 ++++++++ .../traversers/projection_traverser.hpp | 40 ++--- tests/test_subset.cpp | 88 ++++++++++ 17 files changed, 606 insertions(+), 81 deletions(-) create mode 100644 include/samurai/subset/expansion.hpp create mode 100644 include/samurai/subset/traversers/expansion_traverser.hpp create mode 100644 include/samurai/subset/traversers/last_dim_expansion_traverser.hpp diff --git a/demos/FiniteVolume/linear_convection_obstacle.cpp b/demos/FiniteVolume/linear_convection_obstacle.cpp index a39c513e0..57f85a95c 100644 --- a/demos/FiniteVolume/linear_convection_obstacle.cpp +++ b/demos/FiniteVolume/linear_convection_obstacle.cpp @@ -136,7 +136,8 @@ int main(int argc, char* argv[]) } double t = 0; - while (t != Tf) + //~ while (t != Tf) + for (int ite=0; ite!=23; ++ite) { // Move to next timestep t += dt; diff --git a/include/samurai/algorithm/update.hpp b/include/samurai/algorithm/update.hpp index 196e8fed5..3beea8324 100644 --- a/include/samurai/algorithm/update.hpp +++ b/include/samurai/algorithm/update.hpp @@ -18,6 +18,8 @@ #include "graduation.hpp" #include "utils.hpp" +#include "fmt/ranges.h" + #ifndef NDEBUG #include "../io/hdf5.hpp" #endif @@ -133,6 +135,24 @@ namespace samurai auto bc_ghosts_in_other_directions = domain_boundary_outer_layer(mesh, proj_level, n_bc_ghosts); auto projection_ghosts_no_bc_ghosts = difference(projection_ghosts, bc_ghosts_in_other_directions); + + const auto lca_projection_ghosts = projection_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); + const auto lca_projection_ghosts_no_bc_ghosts = projection_ghosts_no_bc_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); + const auto lca_domain = domain.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); + + //// TODO : generate bug, why ? + // const auto lca_expand_projection_ghosts_no_bc_ghosts = expand(projection_ghosts_no_bc_ghosts, expand_width).to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); + + std::system("rm -f bc_ghosts_in_other_directions.*"); + std::system("rm -f projection_ghosts.*"); + std::system("rm -f projection_ghosts_no_bc_ghosts.*"); + std::system("rm -f domain.*"); + + if (!bc_ghosts_in_other_directions.empty()) { save("bc_ghosts_in_other_directions", bc_ghosts_in_other_directions); } + if (!lca_projection_ghosts.empty()) { save("projection_ghosts", lca_projection_ghosts); } + if (!lca_projection_ghosts_no_bc_ghosts.empty()) { save("projection_ghosts_no_bc_ghosts", lca_projection_ghosts_no_bc_ghosts); } + + save("domain", lca_domain); project_bc(projection_ghosts_no_bc_ghosts, proj_level, direction, layer, field); } diff --git a/include/samurai/level_cell_array.hpp b/include/samurai/level_cell_array.hpp index df3214d1b..1396a115c 100644 --- a/include/samurai/level_cell_array.hpp +++ b/include/samurai/level_cell_array.hpp @@ -99,6 +99,9 @@ namespace samurai template LevelCellArray(const SetBase& set); + + template + LevelCellArray(const SetBase& set, const coords_t& origin_point, const double scaling_factor); LevelCellArray(std::size_t level, const Box& box); LevelCellArray(std::size_t level, @@ -371,6 +374,20 @@ namespace samurai }); } + template + template + inline LevelCellArray::LevelCellArray(const SetBase& set, const coords_t& origin_point, const double scaling_factor) + : m_level(set.level()) + , m_origin_point(origin_point) + , m_scaling_factor(scaling_factor) + { + set( + [this](const auto& i, const auto& index) + { + add_interval_back(i, index); + }); + } + //~ template //~ template //~ inline LevelCellArray::LevelCellArray(Subset set) diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index fb87ee1e6..148bfa34a 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -57,12 +57,9 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const { - if constexpr (d != dim - 1) - { - assert(m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]); - } - - return traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]); + return (m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]) + ? traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]) + : traverser_t(0, 0); } private: diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index b33a8956d..c5b113aa0 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -92,25 +92,25 @@ namespace samurai }; template - auto contract(const Set& sets, const typename Contraction>::contraction_t& contraction) + auto contract(const Set& set, const typename Contraction>::contraction_t& contraction) { - return Contraction(self(sets), contraction); + return Contraction(self(set), contraction); } template - auto contract(const Set& sets, const typename Contraction>::value_t contraction) + auto contract(const Set& set, const typename Contraction>::value_t contraction) { - return Contraction(self(sets), contraction); + return Contraction(self(set), contraction); } template - auto contract(const Set& sets, - const typename Contraction>::value_t contraction, - const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this + auto contract(const Set& set, + const typename Contraction>::value_t contraction, + const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this // more readable, // perhaps a traits... { - return Contraction(self(sets), contraction, do_contraction); + return Contraction(self(set), contraction, do_contraction); } } // namespace samurai diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp new file mode 100644 index 000000000..88ebd1b52 --- /dev/null +++ b/include/samurai/subset/expansion.hpp @@ -0,0 +1,164 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_base.hpp" +#include "traversers/expansion_traverser.hpp" +#include "traversers/last_dim_expansion_traverser.hpp" + +namespace samurai +{ + + template + class Expansion; + + template + struct SetTraits> + { + static_assert(IsSet::value); + + template + using traverser_t = std::conditional_t> + , ExpansionTraverser>>; + + static constexpr std::size_t dim = Set::dim; + }; + + namespace detail + { + template + struct ExpansionChildrenTraversers; + + template + struct ExpansionChildrenTraversers> + { + template + using child_traverser_array_t = std::vector< typename Set::template traverser_t >; + + using Type = std::tuple< child_traverser_array_t... >; + + static_assert(std::tuple_size::value == Set::dim-1); + }; + + } // namespace detail + + template + class Expansion : public SetBase> + { + using Self = Expansion; + using ChildrenTraversers = detail::ExpansionChildrenTraversers< Set, std::make_index_sequence >::Type; + public: + + SAMURAI_SET_TYPEDEFS + SAMURAI_SET_CONSTEXPRS + + using expansion_t = std::array; + using do_expansion_t = std::array; + + Expansion(const Set& set, const expansion_t& expansions) + : m_set(set) + , m_expansions(expansions) + { + static_for<0, dim-1>::apply([this](const auto d) + { + std::get(m_children_traversers).reserve(2*m_expansions[d]); + }); + } + + Expansion(const Set& set, const value_t expansion) + : m_set(set) + { + m_expansions.fill(expansion); + static_for<0, dim-1>::apply([this](const auto d) + { + std::get(m_children_traversers).reserve(std::size_t(2*m_expansions[d])); + }); + } + + Expansion(const Set& set, const value_t expansion, const do_expansion_t& do_expansion) + : m_set(set) + { + for (std::size_t i = 0; i != m_expansions.size(); ++i) + { + m_expansions[i] = expansion * do_expansion[i]; + } + + static_for<0, dim-1>::apply([this](const auto d) + { + std::get(m_children_traversers).reserve(2*m_expansions); + }); + } + + inline std::size_t level_impl() const + { + return m_set.level(); + } + + inline bool exist_impl() const + { + return m_set.exist(); + } + + inline bool empty_impl() const + { + return m_set.empty(); + } + + template + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + { + if constexpr (d == dim-1) + { + return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); + } + else + { + auto& children_traversers = std::get(m_children_traversers); + + children_traversers.clear(); + + xt::xtensor_fixed> tmp_index(index); + + for (value_t width=0; width!=m_expansions[d+1]+1; ++width) + { + tmp_index[d+1] = index[d+1] + width; + children_traversers.push_back(m_set.get_traverser(tmp_index, d_ic)); + if (children_traversers.back().is_empty()) { children_traversers.pop_back(); } + + tmp_index[d+1] = index[d+1] - width; + children_traversers.push_back(m_set.get_traverser(tmp_index, d_ic)); + if (children_traversers.back().is_empty()) { children_traversers.pop_back(); } + } + + return traverser_t(children_traversers.begin(), children_traversers.end(), m_expansions[d]); + } + } + + private: + Set m_set; + expansion_t m_expansions; + + mutable ChildrenTraversers m_children_traversers; + }; + + template + auto expand(const Set& set, const typename Contraction>::contraction_t& expansions) + { + return Expansion(self(set), expansions); + } + + template + auto expand(const Set& set, const typename Contraction>::value_t expansion) + { + return Expansion(self(set), expansion); + } + + template + auto expand(const Set& set, const typename Contraction>::value_t expansion, const typename Contraction>::do_expansion_t& do_expansion) + { + return Expansion(self(set), expansion, do_expansion); + } + +} // namespace samurai diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index c8b15a6b1..aa936cf6b 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -32,6 +32,8 @@ namespace samurai SAMURAI_SET_TYPEDEFS SAMURAI_SET_CONSTEXPRS + + using const_interval_iterator = typename std::vector::const_iterator; LCAView(const LCA& lca) : m_lca(lca) @@ -54,37 +56,57 @@ namespace samurai } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - if constexpr (d != dim - 1) + return get_traverser_impl_detail(index, m_lca[dim-1].cbegin(), m_lca[dim-1].cend(), d_ic, std::integral_constant{}); + } + + template + inline traverser_t get_traverser_impl_detail(const index_t& index, const_interval_iterator begin_y_interval, const_interval_iterator end_y_interval, std::integral_constant d_ic, std::integral_constant dCur_ic) const + { + if constexpr (dCur != dim - 1) { - const auto& y = index[d]; - const auto& y_intervals = m_lca[d + 1]; - const auto& y_offsets = m_lca.offsets(d + 1); + const auto& y = index[dCur]; + const auto& y_offsets = m_lca.offsets(dCur + 1); // we need to find an interval that contains y. - const auto y_interval_it = std::find_if(y_intervals.cbegin(), - y_intervals.cend(), + const auto y_interval_it = std::find_if(begin_y_interval, + end_y_interval, [y](const auto& y_interval) { return y_interval.contains(y); }); - if (y_interval_it != y_intervals.cend()) + if (y_interval_it != end_y_interval) { const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); + + const_interval_iterator begin_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]); + const_interval_iterator end_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1]); - return traverser_t(m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]), - m_lca[d].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1])); + return get_traverser_impl_detail_wrapper(index, begin_x_interval, end_x_interval, d_ic, dCur_ic); } else { - return traverser_t(m_lca[d].cend(), m_lca[d].cend()); + return get_traverser_impl_detail_wrapper(index, m_lca[dCur].cend(), m_lca[dCur].cend(), d_ic, dCur_ic); } } else { - return traverser_t(m_lca[d].cbegin(), m_lca[d].cend()); + return get_traverser_impl_detail_wrapper(index, m_lca[dCur].cbegin(), m_lca[dCur].cend(), d_ic, dCur_ic); } } + + template + inline traverser_t get_traverser_impl_detail_wrapper(const index_t& index, const_interval_iterator begin_x_interval, const_interval_iterator end_x_interval, std::integral_constant d_ic, std::integral_constant) const + { + if constexpr (d == dCur) + { + return traverser_t(begin_x_interval, end_x_interval); + } + else + { + return get_traverser_impl_detail(index, begin_x_interval, end_x_interval, d_ic, std::integral_constant{}); + } + } private: diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index ba8011a4c..d1bf53d8c 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -116,40 +116,52 @@ namespace samurai inline bool empty_impl() const { - return std::apply( - [](const auto first_set, const auto&... other_sets) -> std::size_t - { - if constexpr (op == SetOperator::UNION) - { - return first_set.empty() && (other_sets.empty() && ...); - } - else if constexpr (op == SetOperator::INTERSECTION) - { - return first_set.empty() || (other_sets.empty() || ...); - } - else - { - return first_set.empty(); - } - }, - m_sets); + xt::xtensor_fixed> index; + return empty_rec(index, std::integral_constant{}); } template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return get_traverser_impl_impl(index, d_ic, std::make_index_sequence{}); + return get_traverser_impl_detail(index, d_ic, std::make_index_sequence{}); } private: template traverser_t - get_traverser_impl_impl(const index_t& index, std::integral_constant d_ic, std::index_sequence) const + get_traverser_impl_detail(const index_t& index, std::integral_constant d_ic, std::index_sequence) const { return traverser_t(m_shifts, std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic)...); } + template + bool empty_rec(index_t& index, std::integral_constant d_ic) const + { + using current_interval_t = typename traverser_t::current_interval_t; + + for (traverser_t traverser = Base::get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) + { + current_interval_t interval = traverser.current_interval(); + + if constexpr (d == 0) + { + return false; + } + else + { + for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) + { + if (not empty_rec(index, std::integral_constant{})) + { + return false; + } + } + } + } + return true; + } + Childrens m_sets; std::size_t m_level; std::array m_shifts; diff --git a/include/samurai/subset/node.hpp b/include/samurai/subset/node.hpp index e397e33bc..d36aa8009 100644 --- a/include/samurai/subset/node.hpp +++ b/include/samurai/subset/node.hpp @@ -6,6 +6,7 @@ #include "apply.hpp" #include "box_view.hpp" #include "contraction.hpp" +#include "expansion.hpp" #include "lca_view.hpp" #include "nary_set_operator.hpp" #include "projection.hpp" diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index d23bfe75e..0b6890e89 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -4,6 +4,7 @@ #pragma once #include "../samurai_config.hpp" +#include "../static_algorithm.hpp" #include "set_base.hpp" #include "traversers/projection_traverser.hpp" @@ -19,18 +20,31 @@ namespace samurai static_assert(IsSet::value); template - using traverser_t = std::conditional_t, 1>, - ProjectionTraverser, default_config::max_level>>; + using traverser_t = ProjectionTraverser< typename Set::template traverser_t >; static constexpr std::size_t dim = Set::dim; }; + + namespace detail + { + template + struct ProjectionWork; + + template + struct ProjectionWork> + { + template + using child_traverser_array_t = std::vector< typename Set::template traverser_t >; + + using Type = std::tuple< child_traverser_array_t... >; + }; + } // namespace detail template class Projection : public SetBase> { using Self = Projection; - + using Work = typename detail::ProjectionWork< Set, std::make_index_sequence >::Type; public: SAMURAI_SET_TYPEDEFS @@ -69,34 +83,38 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const - { + { + auto& set_traversers = std::get(m_work_traversers); + set_traversers.clear(); + if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != dim - 1) { + //~ set_traversers.reserve(1 << m_shift); + const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; xt::xtensor_fixed> index(_index << m_shift); - //~ std::vector> set_traversers; - //~ set_traversers.reserve(size_t(ymax - ymin)); - FixedCapacityArray, default_config::max_level> set_traversers; - for (index[d] = ymin; index[d] != ymax; ++index[d]) { set_traversers.push_back(m_set.get_traverser(index, d_ic)); + if (set_traversers.back().is_empty()) { set_traversers.pop_back(); } } - return traverser_t(set_traversers, m_shift); + return traverser_t(set_traversers.begin(), set_traversers.end(), m_shift); } else { - return traverser_t(m_set.get_traverser(_index << m_shift, d_ic), m_projectionType, m_shift); + set_traversers.push_back(m_set.get_traverser(_index << m_shift, d_ic)); + return traverser_t(set_traversers.begin(), m_projectionType, m_shift); } } else { - return traverser_t(m_set.get_traverser(_index >> m_shift, d_ic), m_projectionType, m_shift); + set_traversers.push_back(m_set.get_traverser(_index >> m_shift, d_ic)); + return traverser_t(set_traversers.begin(), m_projectionType, m_shift); } } @@ -106,6 +124,8 @@ namespace samurai std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; + + Work m_work_traversers; }; } // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 352424f75..84e845426 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -42,6 +42,9 @@ namespace samurai using traverser_t = typename DerivedTraits::template traverser_t; using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; + + using to_lca_t = LevelCellArray; + using to_lca_coord_t = typename to_lca_t::coords_t; static constexpr std::size_t dim = DerivedTraits::dim; @@ -95,6 +98,16 @@ namespace samurai }; apply(derived_cast(), func); } + + to_lca_t to_lca() const + { + return to_lca_t(*this); + } + + to_lca_t to_lca(const to_lca_coord_t& origin_point, const double scaling_factor) const + { + return to_lca_t(*this, origin_point, scaling_factor); + } }; #define SAMURAI_SET_TYPEDEFS \ diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 8b7722837..8b2b3387b 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -72,8 +72,8 @@ namespace samurai translation_t m_translation; }; - template - auto translate(const Set& set, const translation_t& translation) + template + auto translate(const Set& set, const typename Translation>::translation_t& translation) { return Translation(self(set), translation); } diff --git a/include/samurai/subset/traversers/box_traverser.hpp b/include/samurai/subset/traversers/box_traverser.hpp index 6ca2bc451..e07369c1f 100644 --- a/include/samurai/subset/traversers/box_traverser.hpp +++ b/include/samurai/subset/traversers/box_traverser.hpp @@ -33,7 +33,7 @@ namespace samurai BoxTraverser(const value_t& start, const value_t& end) : m_current_interval{start, end} - , m_empty(false) + , m_empty(start < end) { } diff --git a/include/samurai/subset/traversers/expansion_traverser.hpp b/include/samurai/subset/traversers/expansion_traverser.hpp new file mode 100644 index 000000000..4b1c96fdf --- /dev/null +++ b/include/samurai/subset/traversers/expansion_traverser.hpp @@ -0,0 +1,97 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class ExpansionTraverser; + + template + struct SetTraverserTraits> + { + static_assert(IsSetTraverser::value); + + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class ExpansionTraverser : public SetTraverserBase< ExpansionTraverser > + { + using Self = ExpansionTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + using SetTraverserIterator = typename std::vector::iterator; + + ExpansionTraverser(SetTraverserIterator begin_set_traverser, SetTraverserIterator end_set_traverser, const value_t expansion) + : m_set_traversers(begin_set_traverser, end_set_traverser) + , m_expansion(expansion) + { + assert(m_expansion > 0); + next_interval_impl(); + } + + inline bool is_empty_impl() const + { + return m_current_interval.start == std::numeric_limits::max(); + } + + inline void next_interval_impl() + { + m_current_interval.start = std::numeric_limits::max(); + + // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start + for (const SetTraverser& set_traverser : m_set_traversers) + { + if (!set_traverser.is_empty() && (set_traverser.current_interval().start - m_expansion < m_current_interval.start)) + { + m_current_interval.start = set_traverser.current_interval().start - m_expansion; + m_current_interval.end = set_traverser.current_interval().end + m_expansion; + } + } + // Now we find the end of the interval, i.e. the largest set_traverser.current_interval().end + // such that set_traverser.current_interval().start - expansion < m_current_interval.end + bool is_done = false; + while (!is_done) + { + is_done = true; + // advance set traverses that are behind current interval + for (SetTraverser& set_traverser : m_set_traversers) + { + while (!set_traverser.is_empty() && set_traverser.current_interval().end + m_expansion <= m_current_interval.end) + { + set_traverser.next_interval(); + } + } + // try to find a new end + for (const SetTraverser& set_traverser : m_set_traversers) + { + // there is an overlap + if (!set_traverser.is_empty() && set_traverser.current_interval().start - m_expansion <= m_current_interval.end) + { + is_done = false; + m_current_interval.end = set_traverser.current_interval().end + m_expansion; + } + } + } + } + + inline current_interval_t current_interval_impl() const + { + return m_current_interval; + } + + private: + std::span m_set_traversers; + value_t m_expansion; + interval_t m_current_interval; + bool m_isEmpty; + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp b/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp new file mode 100644 index 000000000..5d591daf0 --- /dev/null +++ b/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp @@ -0,0 +1,73 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_traverser_base.hpp" + +namespace samurai +{ + + template + class LastDimExpansionTraverser; + + template + struct SetTraverserTraits> + { + static_assert(IsSetTraverser::value); + + using interval_t = typename SetTraverserTraits::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class LastDimExpansionTraverser : public SetTraverserBase< LastDimExpansionTraverser > + { + using Self = LastDimExpansionTraverser; + public: + SAMURAI_SET_TRAVERSER_TYPEDEFS + + LastDimExpansionTraverser(const SetTraverser& set_traverser, const value_t expansion) + : m_set_traverser(set_traverser) + , m_expansion(expansion) + { + assert(m_expansion > 0); + next_interval_impl(); + } + + inline bool is_empty_impl() const + { + return m_isEmpty; + } + + inline void next_interval_impl() + { + m_isEmpty = m_set_traverser.is_empty(); + + if (!m_isEmpty) + { + m_current_interval.start = m_set_traverser.current_interval().start - m_expansion; + m_current_interval.end = m_set_traverser.current_interval().end + m_expansion; + + m_set_traverser.next_interval(); + while (!m_set_traverser.is_empty() and m_set_traverser.current_interval().start - m_expansion <= m_current_interval.end) + { + m_current_interval.end = m_set_traverser.current_interval().end + m_expansion; + m_set_traverser.next_interval(); + } + } + } + + inline current_interval_t current_interval_impl() const + { + return m_current_interval; + } + + private: + SetTraverser m_set_traverser; + value_t m_expansion; + interval_t m_current_interval; + bool m_isEmpty; + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 20c8063d9..90a8dcf4a 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -6,8 +6,6 @@ #include "../fixed_capacity_array.hpp" #include "set_traverser_base.hpp" -#include - namespace samurai { enum class ProjectionType @@ -16,11 +14,11 @@ namespace samurai REFINE }; - template + template class ProjectionTraverser; - template - struct SetTraverserTraits> + template + struct SetTraverserTraits> { static_assert(IsSetTraverser::value); @@ -28,23 +26,24 @@ namespace samurai using current_interval_t = const interval_t&; }; - template - class ProjectionTraverser : public SetTraverserBase> + template + class ProjectionTraverser : public SetTraverserBase> { - using Self = ProjectionTraverser; + using Self = ProjectionTraverser; + using SetTraverserIterator = typename std::vector::iterator; public: SAMURAI_SET_TRAVERSER_TYPEDEFS - ProjectionTraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) - : m_projectionType(projectionType) + ProjectionTraverser(SetTraverserIterator set_traverser, const ProjectionType projectionType, const std::size_t shift) + : m_set_traversers(set_traverser, set_traverser + 1) + , m_projectionType(projectionType) , m_shift(shift) - , m_isEmpty(set_traverser.is_empty()) + , m_isEmpty(set_traverser->is_empty()) { - m_set_traversers.push_back(set_traverser); if (!m_isEmpty) - { + { if (m_projectionType == ProjectionType::COARSEN) { m_current_interval.start = coarsen_start(m_set_traversers[0].current_interval()); @@ -61,7 +60,7 @@ namespace samurai } } else - { + { m_current_interval.start = m_set_traversers[0].current_interval().start << shift; m_current_interval.end = m_set_traversers[0].current_interval().end << shift; } @@ -71,8 +70,8 @@ namespace samurai /* * This constructor only works for coarsening */ - ProjectionTraverser(const FixedCapacityArray& set_traversers, const std::size_t shift) - : m_set_traversers(set_traversers) + ProjectionTraverser(SetTraverserIterator begin_set_traversers, SetTraverserIterator end_set_traversers, const std::size_t shift) + : m_set_traversers(begin_set_traversers, end_set_traversers) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) { @@ -154,13 +153,14 @@ namespace samurai return interval.start >> m_shift; } - inline value_t coarsen_end(const interval_t& interval) const + inline value_t coarsen_end(const interval_t& interval) const { - const value_t trial_end = interval.end >> m_shift; - return (trial_end << m_shift) < interval.end ? trial_end + 1 : trial_end; + return ((interval.end - 1) >> m_shift) + 1; + //~ const value_t trial_end = interval.end >> m_shift; + //~ return (trial_end << m_shift) < interval.end ? trial_end + 1 : trial_end; } - FixedCapacityArray m_set_traversers; + std::span m_set_traversers; ProjectionType m_projectionType; std::size_t m_shift; interval_t m_current_interval; diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index e9b152dff..73c229788 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -14,6 +14,9 @@ #include #include +#include +#include + namespace samurai { TEST(subset, lower_bound) @@ -512,6 +515,91 @@ namespace samurai } } + TEST(subset, expand) + { + using interval_t = typename LevelCellArray<2>::interval_t; + using expected_t = std::vector>; + + LevelCellArray<2> ca; + + const int expand_width = 3; + + ca.add_interval_back({0, 1}, {0}); + + { + const auto translated_ca = translate(ca, {expand_width+1, 0}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = expand(joined_cas, expand_width); + + expected_t expected; + for (int w=-expand_width; w!=expand_width+1; ++w) + { + expected.push_back(std::make_pair(w, interval_t{-expand_width, 2*(expand_width + 1)})); + } + + bool is_set_empty = true; + std::size_t ie = 0; + set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) + { + is_set_empty = false; + EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); + }); + EXPECT_FALSE(is_set_empty); + } + + { + const auto translated_ca = translate(ca, {0, expand_width+1}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = expand(joined_cas, expand_width); + + expected_t expected; + for (int w=-expand_width; w!=2*(expand_width+1); ++w) + { + expected.push_back(std::make_pair(w, interval_t{-expand_width, expand_width + 1})); + } + + bool is_set_empty = true; + std::size_t ie = 0; + set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) + { + is_set_empty = false; + EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); + }); + EXPECT_FALSE(is_set_empty); + } + + { + const auto translated_ca = translate(ca, {expand_width+1, expand_width+1}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = expand(joined_cas, expand_width); + + expected_t expected; + for (int w=-expand_width; w!=2*(expand_width+1); ++w) + { + expected.push_back(std::make_pair(w, interval_t{-expand_width, 2*(expand_width+1)})); + } + + bool is_set_empty = true; + std::size_t ie = 0; + set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) + { + is_set_empty = false; + //~ EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); + fmt::print("x_interval = {} -- y = {}\n", x_interval, yz[0]); + }); + EXPECT_FALSE(is_set_empty); + + const auto lca_joined_cas = joined_cas.to_lca(); + const auto lca_set = set.to_lca(); + + save("lca_joined_cas", lca_joined_cas); + save("lca_set", lca_set); + } + } + TEST(subset, translate) { CellList<1> cl; From 25b470f200ea1ca38a5fa083a9a521245f1f79b3 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 11:02:25 +0200 Subject: [PATCH 05/28] memorypool bugged --- include/samurai/subset/memory_pool.hpp | 219 ++++++++++++++++++ include/samurai/subset/projection.hpp | 43 ++-- .../traversers/projection_traverser.hpp | 92 +++++--- include/samurai/subset/work.hpp | 2 + 4 files changed, 311 insertions(+), 45 deletions(-) create mode 100644 include/samurai/subset/memory_pool.hpp create mode 100644 include/samurai/subset/work.hpp diff --git a/include/samurai/subset/memory_pool.hpp b/include/samurai/subset/memory_pool.hpp new file mode 100644 index 000000000..39cb8b823 --- /dev/null +++ b/include/samurai/subset/memory_pool.hpp @@ -0,0 +1,219 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include +#include +#include +#include +#include + +#include + +template> +class MemoryPool +{ +public: + using Allocator = typename std::allocator_traits::template rebind_alloc; + using AllocatorTraits = std::allocator_traits; + using Element = typename AllocatorTraits::value_type; + using Pointer = typename AllocatorTraits::pointer; + using const_Pointer = typename AllocatorTraits::const_pointer; + using Reference = Element&; + using const_Reference = const Element&; + using Distance = typename AllocatorTraits::difference_type; + using Size = typename AllocatorTraits::size_type; + using OffsetRange = std::ranges::iota_view; + + static_assert(std::is_move_constructible::value or std::is_trivially_copyable::value); + + struct Chunk + { + Distance offset; + Size size; + bool isFree; + + friend bool operator<(const Chunk& lhs, const Chunk& rhs) { return lhs.offset < rhs.offset; } + }; + + using ChunkIterator = typename std::vector::iterator; + + MemoryPool(const MemoryPool&) = delete; + MemoryPool& operator=(const MemoryPool&) = delete; + + ~MemoryPool(); + + OffsetRange requestChunk(const Size chunkSize); + + void freeChunk(const OffsetRange offsets); + + Pointer getPtr(const Distance offset) { assert(Size(offset) < m_totalSize); return m_memory + offset; } + const_Pointer getPtr(const Distance offset) const { assert(Size(offset) < m_totalSize); return m_memory + offset; } + + Reference at(const Distance offset) { return *getPtr(offset); } + const_Reference at(const Distance offset) const { return *getPtr(offset); } + + Reference operator[](const Distance offset) { return at(offset); } + const_Reference operator[](const Distance offset) const { return at(offset); } + + Size totalSize() const { return m_totalSize; } + + static MemoryPool& getInstance(); +private: + MemoryPool() {} + + Pointer m_memory = nullptr; + Size m_totalSize = 0; + Allocator m_allocator; + std::vector m_chunks; +}; + +template +MemoryPool& MemoryPool::getInstance() +{ + static MemoryPool instance; + + return instance; +} + +template +MemoryPool::~MemoryPool() +{ + assert(std::all_of(std::begin(m_chunks), std::end(m_chunks), [](const Chunk& chunk) -> bool + { + return chunk.isFree; + })); + + m_allocator.deallocate(m_memory, m_totalSize); + + m_memory = nullptr; + m_totalSize = 0; +} + +template +auto MemoryPool::requestChunk(const Size chunkSize) -> OffsetRange +{ + const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), std::end(m_chunks), [chunkSize](const Chunk& chunk) -> bool + { + return chunk.isFree and chunk.size >= chunkSize; + }); + + if (chunkIt != std::end(m_chunks)) + { + chunkIt->isFree = false; + const OffsetRange ret(chunkIt->offset, chunkIt->offset + Distance(chunkSize)); + + if (chunkIt->size > chunkSize) + { + // slipt the chunk + const Distance newChunkOffset = chunkIt->offset + Distance(chunkSize); + const Size newChunkSize = chunkIt->size - chunkSize; + + chunkIt->size = chunkSize; + m_chunks.push_back({.offset = newChunkOffset, .size = newChunkSize, .isFree = true}); + } + + fmt::print("returning chunk {} of {}\n", fmt::join(ret, ", "), typeid(T).name()); + + return ret; + } + else if (m_memory != nullptr) + { + const Size newTotalSize = std::max(m_totalSize + chunkSize, 2*m_totalSize); + // we need to reallocate a larger buffer + Pointer newMemory = m_allocator.allocate(newTotalSize); + // we need to move all the data from our buffer to the new one + auto usedChunks = m_chunks | std::views::filter([] (const Chunk& chunk) { return not chunk.isFree; }); + + for (const Chunk& chunk : usedChunks) + { + Pointer beginChunk = m_memory + chunk.offset; + Pointer endChunk = beginChunk + chunk.size; + Pointer dstIt = newMemory + chunk.offset; + if constexpr (std::is_trivially_copyable::value) + { + std::copy(beginChunk, endChunk, dstIt); + std::destroy(beginChunk, endChunk); + } + else + { + for (Pointer srcIt=beginChunk; srcIt!=endChunk; ++srcIt, ++dstIt) + { + std::construct_at(dstIt, std::move(*srcIt)); + std::destroy_at(srcIt); + } + } + } + // now we can swap the pointers and free newMemory + std::swap(m_memory, newMemory); + m_allocator.deallocate(newMemory, m_totalSize); + + // now we create a new chunk with the correct size + + m_chunks.push_back({.offset = Distance(m_totalSize), .size = chunkSize, .isFree = false}); + OffsetRange ret(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); + + if (newTotalSize != (m_totalSize + chunkSize)) + { + m_chunks.push_back({.offset = Distance(m_totalSize + chunkSize), .size = Size(newTotalSize - m_totalSize - chunkSize), .isFree = true}); + } + m_totalSize = newTotalSize; + + fmt::print("returning chunk {} of {}\n", fmt::join(ret, ", "), typeid(T).name()); + + return ret; + } + else + { + m_memory = m_allocator.allocate(chunkSize); + m_totalSize = chunkSize; + + m_chunks.push_back({.offset = 0, .size = chunkSize, .isFree = false}); + + fmt::print("returning chunk {} of {}\n", fmt::join(OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)), ", "), typeid(T).name()); + + return OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); + } +} + +template +auto MemoryPool::freeChunk(const OffsetRange offsets) -> void +{ + const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), std::end(m_chunks), [&offsets](const Chunk& chunk) -> bool + { + return (not chunk.isFree) and chunk.offset == offsets[0] and chunk.size == offsets.size(); + }); + + fmt::print("freeing {} of {}\n", fmt::join(offsets, ", "), typeid(T).name()); + + assert(chunkIt != std::end(m_chunks)); + + if (chunkIt != std::end(m_chunks)) + { + chunkIt->isFree = true; + + std::destroy(m_memory + chunkIt->offset, m_memory + chunkIt->offset + chunkIt->size); + + // Coalescing + std::sort(std::begin(m_chunks), std::end(m_chunks)); + + for (ChunkIterator it=std::begin(m_chunks); it!=std::end(m_chunks); ++it) + { + if (it->isFree) + { + for (auto nextIt=std::next(it); nextIt!=std::end(m_chunks) and nextIt->isFree and it->offset + Distance(it->size) == nextIt->offset; ++nextIt) + { + it->size += nextIt->size; + nextIt->size = 0; // mark for removal with std::remove_if + } + } + } + + const ChunkIterator newEnd = std::remove_if(std::begin(m_chunks), std::end(m_chunks), [](const Chunk& chunk) -> bool + { + return chunk.size == 0; + }); + m_chunks.erase(newEnd, std::end(m_chunks)); + } +} diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 0b6890e89..ca0bab54a 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -6,6 +6,7 @@ #include "../samurai_config.hpp" #include "../static_algorithm.hpp" #include "set_base.hpp" +#include "memory_pool.hpp" #include "traversers/projection_traverser.hpp" namespace samurai @@ -34,9 +35,15 @@ namespace samurai struct ProjectionWork> { template - using child_traverser_array_t = std::vector< typename Set::template traverser_t >; + using child_traverser_t = typename Set::template traverser_t; - using Type = std::tuple< child_traverser_array_t... >; + template + using child_traverser_array_t = std::vector< child_traverser_t >; + + template + using array_of_child_traverser_array_t = std::vector< child_traverser_array_t >; + + using Type = std::tuple< array_of_child_traverser_array_t... >; }; } // namespace detail @@ -44,7 +51,6 @@ namespace samurai class Projection : public SetBase> { using Self = Projection; - using Work = typename detail::ProjectionWork< Set, std::make_index_sequence >::Type; public: SAMURAI_SET_TYPEDEFS @@ -83,15 +89,18 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const - { - auto& set_traversers = std::get(m_work_traversers); - set_traversers.clear(); + { + using Work = MemoryPool< typename Set::template traverser_t >; + + Work& work = Work::getInstance(); if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != dim - 1) { - //~ set_traversers.reserve(1 << m_shift); + const auto set_traversers_offsets = work.requestChunk( 1 << m_shift ); + + auto end_offset = set_traversers_offsets[0]; const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; @@ -100,21 +109,25 @@ namespace samurai for (index[d] = ymin; index[d] != ymax; ++index[d]) { - set_traversers.push_back(m_set.get_traverser(index, d_ic)); - if (set_traversers.back().is_empty()) { set_traversers.pop_back(); } + std::construct_at(work.getPtr(end_offset), m_set.get_traverser(index, d_ic)); + ++end_offset; } - return traverser_t(set_traversers.begin(), set_traversers.end(), m_shift); + return traverser_t(set_traversers_offsets[0], end_offset, m_shift); } else { - set_traversers.push_back(m_set.get_traverser(_index << m_shift, d_ic)); - return traverser_t(set_traversers.begin(), m_projectionType, m_shift); + const auto set_traversers_offsets = work.requestChunk( 1 ); + std::construct_at(work.getPtr(set_traversers_offsets[0]), m_set.get_traverser(_index << m_shift, d_ic)); + + return traverser_t(set_traversers_offsets[0], m_projectionType, m_shift); } } else { - set_traversers.push_back(m_set.get_traverser(_index >> m_shift, d_ic)); - return traverser_t(set_traversers.begin(), m_projectionType, m_shift); + const auto set_traversers_offsets = work.requestChunk( 1 ); + std::construct_at(work.getPtr(set_traversers_offsets[0]), m_set.get_traverser(_index >> m_shift, d_ic)); + + return traverser_t(set_traversers_offsets[0], m_projectionType, m_shift); } } @@ -124,8 +137,6 @@ namespace samurai std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; - - Work m_work_traversers; }; } // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 90a8dcf4a..44fc7e005 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -4,6 +4,7 @@ #pragma once #include "../fixed_capacity_array.hpp" +#include "../memory_pool.hpp" #include "set_traverser_base.hpp" namespace samurai @@ -30,39 +31,47 @@ namespace samurai class ProjectionTraverser : public SetTraverserBase> { using Self = ProjectionTraverser; - using SetTraverserIterator = typename std::vector::iterator; + //~ using SetTraverserIterator = typename std::vector::iterator; + + using SetTraverserOffsetRange = MemoryPool::OffsetRange; + using SetTraverserOffset = MemoryPool::Distance; public: SAMURAI_SET_TRAVERSER_TYPEDEFS - ProjectionTraverser(SetTraverserIterator set_traverser, const ProjectionType projectionType, const std::size_t shift) - : m_set_traversers(set_traverser, set_traverser + 1) + ProjectionTraverser(SetTraverserOffset set_traverser_offset, const ProjectionType projectionType, const std::size_t shift) + : m_set_traverser_offsets(set_traverser_offset, set_traverser_offset + 1) + , m_is_work_freed(false) , m_projectionType(projectionType) , m_shift(shift) - , m_isEmpty(set_traverser->is_empty()) + , m_isEmpty(MemoryPool::getInstance().at(set_traverser_offset).is_empty()) { + fmt::print("constructed with chunk {} of {}\n", fmt::join(m_set_traverser_offsets, ", "), typeid(SetTraverser).name()); + + const auto set_traversers = get_set_traversers_view(); + if (!m_isEmpty) { if (m_projectionType == ProjectionType::COARSEN) { - m_current_interval.start = coarsen_start(m_set_traversers[0].current_interval()); - m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); + m_current_interval.start = coarsen_start(set_traversers[0].current_interval()); + m_current_interval.end = coarsen_end(set_traversers[0].current_interval()); - m_set_traversers[0].next_interval(); + set_traversers[0].next_interval(); // when coarsening, two disjoint intervals may be merged. // we need to check if the next_interval overlaps - for (; !m_set_traversers[0].is_empty() && coarsen_start(m_set_traversers[0].current_interval()) <= m_current_interval.end; - m_set_traversers[0].next_interval()) + for (; !set_traversers[0].is_empty() && coarsen_start(set_traversers[0].current_interval()) <= m_current_interval.end; + set_traversers[0].next_interval()) { - m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); + m_current_interval.end = coarsen_end(set_traversers[0].current_interval()); } } else { - m_current_interval.start = m_set_traversers[0].current_interval().start << shift; - m_current_interval.end = m_set_traversers[0].current_interval().end << shift; + m_current_interval.start = set_traversers[0].current_interval().start << shift; + m_current_interval.end = set_traversers[0].current_interval().end << shift; } } } @@ -70,34 +79,44 @@ namespace samurai /* * This constructor only works for coarsening */ - ProjectionTraverser(SetTraverserIterator begin_set_traversers, SetTraverserIterator end_set_traversers, const std::size_t shift) - : m_set_traversers(begin_set_traversers, end_set_traversers) + ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset last_set_traverser_offset, const std::size_t shift) + : m_set_traverser_offsets(first_set_traverser_offset, last_set_traverser_offset) + , m_is_work_freed(false) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) { + fmt::print("constructed with chunk {} of {}\n", fmt::join(m_set_traverser_offsets, ", "), typeid(SetTraverser).name()); + next_interval_coarsen(); } inline bool is_empty_impl() const - { + { return m_isEmpty; } inline void next_interval_impl() { + const auto set_traversers = get_set_traversers_view(); + if (m_projectionType == ProjectionType::COARSEN) { next_interval_coarsen(); } else { - m_set_traversers[0].next_interval(); - m_isEmpty = m_set_traversers[0].is_empty(); + set_traversers[0].next_interval(); + m_isEmpty = set_traversers[0].is_empty(); if (!m_isEmpty) { - m_current_interval.start = m_set_traversers[0].current_interval().start << m_shift; - m_current_interval.end = m_set_traversers[0].current_interval().end << m_shift; + m_current_interval.start = set_traversers[0].current_interval().start << m_shift; + m_current_interval.end = set_traversers[0].current_interval().end << m_shift; } + else if (not m_is_work_freed) + { + MemoryPool::getInstance().freeChunk(m_set_traverser_offsets); + m_is_work_freed = true; + } } } @@ -107,12 +126,22 @@ namespace samurai } private: + + inline auto get_set_traversers_view() + { + return m_set_traverser_offsets | std::views::transform([&pool = MemoryPool::getInstance()](const SetTraverserOffset& offset) -> SetTraverser& + { + return pool.at(offset); + }); + } inline void next_interval_coarsen() { + const auto set_traversers = get_set_traversers_view(); + m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift - for (const SetTraverser& set_traverser : m_set_traversers) + for (const SetTraverser& set_traverser : set_traversers) { if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) < m_current_interval.start)) { @@ -127,7 +156,7 @@ namespace samurai { is_done = true; // advance set traverses that are behind current interval - for (SetTraverser& set_traverser : m_set_traversers) + for (SetTraverser& set_traverser : set_traversers) { while (!set_traverser.is_empty() && (coarsen_end(set_traverser.current_interval()) <= m_current_interval.end)) { @@ -135,7 +164,7 @@ namespace samurai } } // try to find a new end - for (const SetTraverser& set_traverser : m_set_traversers) + for (const SetTraverser& set_traverser : set_traversers) { // there is an overlap if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) <= m_current_interval.end)) @@ -146,6 +175,12 @@ namespace samurai } } m_isEmpty = (m_current_interval.start == std::numeric_limits::max()); + + if (m_isEmpty and not m_is_work_freed) + { + MemoryPool::getInstance().freeChunk(m_set_traverser_offsets); + m_is_work_freed = true; + } } inline value_t coarsen_start(const interval_t& interval) const @@ -156,15 +191,14 @@ namespace samurai inline value_t coarsen_end(const interval_t& interval) const { return ((interval.end - 1) >> m_shift) + 1; - //~ const value_t trial_end = interval.end >> m_shift; - //~ return (trial_end << m_shift) < interval.end ? trial_end + 1 : trial_end; } - std::span m_set_traversers; - ProjectionType m_projectionType; - std::size_t m_shift; - interval_t m_current_interval; - bool m_isEmpty; + SetTraverserOffsetRange m_set_traverser_offsets; + bool m_is_work_freed; + ProjectionType m_projectionType; + std::size_t m_shift; + interval_t m_current_interval; + bool m_isEmpty; }; } // namespace samurai diff --git a/include/samurai/subset/work.hpp b/include/samurai/subset/work.hpp new file mode 100644 index 000000000..929a89fa5 --- /dev/null +++ b/include/samurai/subset/work.hpp @@ -0,0 +1,2 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause From c2682ebfce9874528c7f65799a5770a5d447c5c8 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 14:41:05 +0200 Subject: [PATCH 06/28] memorypool and projection corrected - expand is next --- include/samurai/subset/apply.hpp | 3 +- include/samurai/subset/contraction.hpp | 2 +- include/samurai/subset/memory_pool.hpp | 8 -- include/samurai/subset/nary_set_operator.hpp | 30 +----- include/samurai/subset/projection.hpp | 51 +++++++++- include/samurai/subset/set_base.hpp | 33 +++++++ .../traversers/contraction_traverser.hpp | 14 ++- .../traversers/projection_traverser.hpp | 20 +--- tests/test_subset.cpp | 95 +++++++++++++------ 9 files changed, 163 insertions(+), 93 deletions(-) diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index 5e1978220..c78176ea6 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -16,8 +16,9 @@ namespace samurai using current_interval_t = typename traverser_t::current_interval_t; for (traverser_t traverser = set.get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) - { + { current_interval_t interval = traverser.current_interval(); + if constexpr (d == 0) { func(interval, index); diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index c5b113aa0..6cec5c8b4 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -76,7 +76,7 @@ namespace samurai inline bool empty_impl() const { - return m_set.empty(); + return Base::empty_default_impl(); } template diff --git a/include/samurai/subset/memory_pool.hpp b/include/samurai/subset/memory_pool.hpp index 39cb8b823..4c296d415 100644 --- a/include/samurai/subset/memory_pool.hpp +++ b/include/samurai/subset/memory_pool.hpp @@ -114,8 +114,6 @@ auto MemoryPool::requestChunk(const Size chunkSize) -> Offse m_chunks.push_back({.offset = newChunkOffset, .size = newChunkSize, .isFree = true}); } - fmt::print("returning chunk {} of {}\n", fmt::join(ret, ", "), typeid(T).name()); - return ret; } else if (m_memory != nullptr) @@ -160,8 +158,6 @@ auto MemoryPool::requestChunk(const Size chunkSize) -> Offse } m_totalSize = newTotalSize; - fmt::print("returning chunk {} of {}\n", fmt::join(ret, ", "), typeid(T).name()); - return ret; } else @@ -171,8 +167,6 @@ auto MemoryPool::requestChunk(const Size chunkSize) -> Offse m_chunks.push_back({.offset = 0, .size = chunkSize, .isFree = false}); - fmt::print("returning chunk {} of {}\n", fmt::join(OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)), ", "), typeid(T).name()); - return OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); } } @@ -185,8 +179,6 @@ auto MemoryPool::freeChunk(const OffsetRange offsets) -> voi return (not chunk.isFree) and chunk.offset == offsets[0] and chunk.size == offsets.size(); }); - fmt::print("freeing {} of {}\n", fmt::join(offsets, ", "), typeid(T).name()); - assert(chunkIt != std::end(m_chunks)); if (chunkIt != std::end(m_chunks)) diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index d1bf53d8c..fef64f6d8 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -116,8 +116,7 @@ namespace samurai inline bool empty_impl() const { - xt::xtensor_fixed> index; - return empty_rec(index, std::integral_constant{}); + return Base::empty_default_impl(); } template @@ -135,33 +134,6 @@ namespace samurai return traverser_t(m_shifts, std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic)...); } - template - bool empty_rec(index_t& index, std::integral_constant d_ic) const - { - using current_interval_t = typename traverser_t::current_interval_t; - - for (traverser_t traverser = Base::get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) - { - current_interval_t interval = traverser.current_interval(); - - if constexpr (d == 0) - { - return false; - } - else - { - for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) - { - if (not empty_rec(index, std::integral_constant{})) - { - return false; - } - } - } - } - return true; - } - Childrens m_sets; std::size_t m_level; std::array m_shifts; diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index ca0bab54a..8a6ce0ad0 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -38,12 +38,12 @@ namespace samurai using child_traverser_t = typename Set::template traverser_t; template - using child_traverser_array_t = std::vector< child_traverser_t >; + using child_traverser_offset_range_t = typename MemoryPool< child_traverser_t >::OffsetRange; template - using array_of_child_traverser_array_t = std::vector< child_traverser_array_t >; + using array_of_child_traverser_offset_range_t = std::vector< child_traverser_offset_range_t >; - using Type = std::tuple< array_of_child_traverser_array_t... >; + using Type = std::tuple< array_of_child_traverser_offset_range_t... >; }; } // namespace detail @@ -51,6 +51,7 @@ namespace samurai class Projection : public SetBase> { using Self = Projection; + using OffsetRangeWork = detail::ProjectionWork< Set, std::make_index_sequence >::Type; public: SAMURAI_SET_TYPEDEFS @@ -72,6 +73,39 @@ namespace samurai } } + // we need to define a custom copy and move constructor because + // we do not want to copy m_work_offsetRanges + Projection(const Projection& other) + : m_set(other.m_set) + , m_level(other.m_level) + , m_projectionType(other.m_projectionType) + , m_shift(other.m_shift) + { + } + + Projection(Projection&& other) + : m_set(std::move(other.m_set)) + , m_level(std::move(other.m_level)) + , m_projectionType(std::move(other.m_projectionType)) + , m_shift(std::move(other.m_shift)) + { + } + + ~Projection() + { + static_for<0, dim>::apply([this](const auto d) + { + using Work = MemoryPool< typename Set::template traverser_t< d > >; + + auto& work = Work::getInstance(); + + for (auto& offset_range : std::get(m_work_offsetRanges)) + { + work.freeChunk(offset_range); + } + }); + } + inline std::size_t level_impl() const { return m_level; @@ -94,6 +128,8 @@ namespace samurai Work& work = Work::getInstance(); + auto& offsetRange = std::get(m_work_offsetRanges); + if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != dim - 1) @@ -112,6 +148,9 @@ namespace samurai std::construct_at(work.getPtr(end_offset), m_set.get_traverser(index, d_ic)); ++end_offset; } + + offsetRange.push_back(set_traversers_offsets); + return traverser_t(set_traversers_offsets[0], end_offset, m_shift); } else @@ -119,6 +158,8 @@ namespace samurai const auto set_traversers_offsets = work.requestChunk( 1 ); std::construct_at(work.getPtr(set_traversers_offsets[0]), m_set.get_traverser(_index << m_shift, d_ic)); + offsetRange.push_back(set_traversers_offsets); + return traverser_t(set_traversers_offsets[0], m_projectionType, m_shift); } } @@ -126,6 +167,8 @@ namespace samurai { const auto set_traversers_offsets = work.requestChunk( 1 ); std::construct_at(work.getPtr(set_traversers_offsets[0]), m_set.get_traverser(_index >> m_shift, d_ic)); + + offsetRange.push_back(set_traversers_offsets); return traverser_t(set_traversers_offsets[0], m_projectionType, m_shift); } @@ -137,6 +180,8 @@ namespace samurai std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; + + mutable OffsetRangeWork m_work_offsetRanges; }; } // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 84e845426..dbea148c1 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -108,6 +108,39 @@ namespace samurai { return to_lca_t(*this, origin_point, scaling_factor); } + protected: + inline bool empty_default_impl() const + { + xt::xtensor_fixed> index; + return empty_default_impl_rec(index, std::integral_constant{}); + } + + template + bool empty_default_impl_rec(index_t& index, std::integral_constant d_ic) const + { + using current_interval_t = typename traverser_t::current_interval_t; + + for (traverser_t traverser = get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) + { + current_interval_t interval = traverser.current_interval(); + + if constexpr (d == 0) + { + return false; + } + else + { + for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) + { + if (not empty_default_impl_rec(index, std::integral_constant{})) + { + return false; + } + } + } + } + return true; + } }; #define SAMURAI_SET_TYPEDEFS \ diff --git a/include/samurai/subset/traversers/contraction_traverser.hpp b/include/samurai/subset/traversers/contraction_traverser.hpp index a6e3314e2..b2fbc7a27 100644 --- a/include/samurai/subset/traversers/contraction_traverser.hpp +++ b/include/samurai/subset/traversers/contraction_traverser.hpp @@ -34,6 +34,7 @@ namespace samurai , m_contraction(contraction) { assert(m_contraction >= 0); + advance_to_next_valid_interval(); } inline bool is_empty_impl() const @@ -44,10 +45,7 @@ namespace samurai inline void next_interval_impl() { m_set_traverser.next_interval(); - while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) - { - m_set_traverser.next_interval(); - } + advance_to_next_valid_interval(); } inline current_interval_t current_interval_impl() const @@ -58,6 +56,14 @@ namespace samurai private: + inline void advance_to_next_valid_interval() + { + while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) + { + m_set_traverser.next_interval(); + } + } + SetTraverser m_set_traverser; value_t m_contraction; }; diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 44fc7e005..2266250b1 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -42,13 +42,10 @@ namespace samurai ProjectionTraverser(SetTraverserOffset set_traverser_offset, const ProjectionType projectionType, const std::size_t shift) : m_set_traverser_offsets(set_traverser_offset, set_traverser_offset + 1) - , m_is_work_freed(false) , m_projectionType(projectionType) , m_shift(shift) , m_isEmpty(MemoryPool::getInstance().at(set_traverser_offset).is_empty()) { - fmt::print("constructed with chunk {} of {}\n", fmt::join(m_set_traverser_offsets, ", "), typeid(SetTraverser).name()); - const auto set_traversers = get_set_traversers_view(); if (!m_isEmpty) @@ -81,12 +78,9 @@ namespace samurai */ ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset last_set_traverser_offset, const std::size_t shift) : m_set_traverser_offsets(first_set_traverser_offset, last_set_traverser_offset) - , m_is_work_freed(false) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) - { - fmt::print("constructed with chunk {} of {}\n", fmt::join(m_set_traverser_offsets, ", "), typeid(SetTraverser).name()); - + { next_interval_coarsen(); } @@ -112,11 +106,6 @@ namespace samurai m_current_interval.start = set_traversers[0].current_interval().start << m_shift; m_current_interval.end = set_traversers[0].current_interval().end << m_shift; } - else if (not m_is_work_freed) - { - MemoryPool::getInstance().freeChunk(m_set_traverser_offsets); - m_is_work_freed = true; - } } } @@ -175,12 +164,6 @@ namespace samurai } } m_isEmpty = (m_current_interval.start == std::numeric_limits::max()); - - if (m_isEmpty and not m_is_work_freed) - { - MemoryPool::getInstance().freeChunk(m_set_traverser_offsets); - m_is_work_freed = true; - } } inline value_t coarsen_start(const interval_t& interval) const @@ -194,7 +177,6 @@ namespace samurai } SetTraverserOffsetRange m_set_traverser_offsets; - bool m_is_work_freed; ProjectionType m_projectionType; std::size_t m_shift; interval_t m_current_interval; diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 73c229788..85e1ee734 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -522,21 +522,23 @@ namespace samurai LevelCellArray<2> ca; - const int expand_width = 3; - ca.add_interval_back({0, 1}, {0}); { - const auto translated_ca = translate(ca, {expand_width+1, 0}); + const auto translated_ca = translate(ca, {3 + 1, 0}); const auto joined_cas = union_(ca, translated_ca); - const auto set = expand(joined_cas, expand_width); + const auto set = expand(joined_cas, 3); - expected_t expected; - for (int w=-expand_width; w!=expand_width+1; ++w) - { - expected.push_back(std::make_pair(w, interval_t{-expand_width, 2*(expand_width + 1)})); - } + expected_t expected{ + {-3, {-3, 8}}, + {-2, {-3, 8}}, + {-1, {-3, 8}}, + { 0, {-3, 8}}, + { 1, {-3, 8}}, + { 2, {-3, 8}}, + { 3, {-3, 8}} + }; bool is_set_empty = true; std::size_t ie = 0; @@ -545,20 +547,29 @@ namespace samurai is_set_empty = false; EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); }); + EXPECT_EQ(ie, expected.size()); EXPECT_FALSE(is_set_empty); } { - const auto translated_ca = translate(ca, {0, expand_width+1}); + const auto translated_ca = translate(ca, {0, 3+1}); const auto joined_cas = union_(ca, translated_ca); - const auto set = expand(joined_cas, expand_width); + const auto set = expand(joined_cas, 3); - expected_t expected; - for (int w=-expand_width; w!=2*(expand_width+1); ++w) - { - expected.push_back(std::make_pair(w, interval_t{-expand_width, expand_width + 1})); - } + expected_t expected{ + {-3, {-3, 4}}, + {-2, {-3, 4}}, + {-1, {-3, 4}}, + { 0, {-3, 4}}, + { 1, {-3, 4}}, + { 2, {-3, 4}}, + { 3, {-3, 4}}, + { 4, {-3, 4}}, + { 5, {-3, 4}}, + { 6, {-3, 4}}, + { 7, {-3, 4}} + }; bool is_set_empty = true; std::size_t ie = 0; @@ -567,36 +578,64 @@ namespace samurai is_set_empty = false; EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); }); + EXPECT_EQ(ie, expected.size()); EXPECT_FALSE(is_set_empty); } - { - const auto translated_ca = translate(ca, {expand_width+1, expand_width+1}); + const auto translated_ca = translate(ca, {3+1, 3+1}); const auto joined_cas = union_(ca, translated_ca); - const auto set = expand(joined_cas, expand_width); + const auto set = expand(joined_cas, 3); - expected_t expected; - for (int w=-expand_width; w!=2*(expand_width+1); ++w) - { - expected.push_back(std::make_pair(w, interval_t{-expand_width, 2*(expand_width+1)})); - } + expected_t expected{ + {-3, {-3, 4}}, + {-2, {-3, 4}}, + {-1, {-3, 4}}, + { 0, {-3, 4}}, + { 1, {-3, 8}}, + { 2, {-3, 8}}, + { 3, {-3, 8}}, + { 4, { 1, 8}}, + { 5, { 1, 8}}, + { 6, { 1, 8}}, + { 7, { 1, 8}} + }; bool is_set_empty = true; std::size_t ie = 0; set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) { is_set_empty = false; - //~ EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); - fmt::print("x_interval = {} -- y = {}\n", x_interval, yz[0]); + EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); }); + EXPECT_EQ(ie, expected.size()); EXPECT_FALSE(is_set_empty); const auto lca_joined_cas = joined_cas.to_lca(); const auto lca_set = set.to_lca(); + } + } + + TEST(subset, contract) + { + LevelCellArray<2> ca; + + ca.add_interval_back({0, 1}, {0}); + + { + const auto translated_ca = translate(ca, {3 + 1, 0}); + const auto joined_cas = union_(ca, translated_ca); - save("lca_joined_cas", lca_joined_cas); - save("lca_set", lca_set); + const auto set = contract(joined_cas, 1); + + bool is_set_empty = true; + set([&is_set_empty](const auto& x_interval, const auto& yz) + { + fmt::print("x_interval = {} -- yz = {}", x_interval, yz[0]); + is_set_empty = false; + }); + EXPECT_TRUE(is_set_empty); + //~ EXPECT_TRUE(set.empty()); } } From 1015846cc52fcceb33fbc56ac18013fa63a6c151 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 16:50:40 +0200 Subject: [PATCH 07/28] stuff --- include/samurai/algorithm/update.hpp | 14 ---- include/samurai/subset/expansion.hpp | 81 +++++++++++++------ include/samurai/subset/memory_pool.hpp | 12 ++- include/samurai/subset/projection.hpp | 21 +++-- .../subset/traversers/expansion_traverser.hpp | 23 ++++-- .../traversers/projection_traverser.hpp | 71 ++++++++-------- 6 files changed, 124 insertions(+), 98 deletions(-) diff --git a/include/samurai/algorithm/update.hpp b/include/samurai/algorithm/update.hpp index 3beea8324..9a6ce5b2b 100644 --- a/include/samurai/algorithm/update.hpp +++ b/include/samurai/algorithm/update.hpp @@ -139,20 +139,6 @@ namespace samurai const auto lca_projection_ghosts = projection_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); const auto lca_projection_ghosts_no_bc_ghosts = projection_ghosts_no_bc_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); const auto lca_domain = domain.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); - - //// TODO : generate bug, why ? - // const auto lca_expand_projection_ghosts_no_bc_ghosts = expand(projection_ghosts_no_bc_ghosts, expand_width).to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); - - std::system("rm -f bc_ghosts_in_other_directions.*"); - std::system("rm -f projection_ghosts.*"); - std::system("rm -f projection_ghosts_no_bc_ghosts.*"); - std::system("rm -f domain.*"); - - if (!bc_ghosts_in_other_directions.empty()) { save("bc_ghosts_in_other_directions", bc_ghosts_in_other_directions); } - if (!lca_projection_ghosts.empty()) { save("projection_ghosts", lca_projection_ghosts); } - if (!lca_projection_ghosts_no_bc_ghosts.empty()) { save("projection_ghosts_no_bc_ghosts", lca_projection_ghosts_no_bc_ghosts); } - - save("domain", lca_domain); project_bc(projection_ghosts_no_bc_ghosts, proj_level, direction, layer, field); } diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 88ebd1b52..1908e1008 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -29,15 +29,18 @@ namespace samurai namespace detail { template - struct ExpansionChildrenTraversers; + struct ExpansionWork; template - struct ExpansionChildrenTraversers> + struct ExpansionWork> { template - using child_traverser_array_t = std::vector< typename Set::template traverser_t >; + using child_traverser_t = typename Set::template traverser_t; + + template + using array_of_child_traverser_offset_range_t = std::vector< typename MemoryPool< child_traverser_t >::OffsetRange >; - using Type = std::tuple< child_traverser_array_t... >; + using Type = std::tuple< array_of_child_traverser_offset_range_t... >; static_assert(std::tuple_size::value == Set::dim-1); }; @@ -48,7 +51,7 @@ namespace samurai class Expansion : public SetBase> { using Self = Expansion; - using ChildrenTraversers = detail::ExpansionChildrenTraversers< Set, std::make_index_sequence >::Type; + using OffsetRangeWork = detail::ExpansionWork< Set, std::make_index_sequence >::Type; public: SAMURAI_SET_TYPEDEFS @@ -61,20 +64,12 @@ namespace samurai : m_set(set) , m_expansions(expansions) { - static_for<0, dim-1>::apply([this](const auto d) - { - std::get(m_children_traversers).reserve(2*m_expansions[d]); - }); } Expansion(const Set& set, const value_t expansion) : m_set(set) { m_expansions.fill(expansion); - static_for<0, dim-1>::apply([this](const auto d) - { - std::get(m_children_traversers).reserve(std::size_t(2*m_expansions[d])); - }); } Expansion(const Set& set, const value_t expansion, const do_expansion_t& do_expansion) @@ -84,11 +79,35 @@ namespace samurai { m_expansions[i] = expansion * do_expansion[i]; } - + } + + // we need to define a custom copy and move constructor because + // we do not want to copy m_work_offsetRanges + Expansion(const Expansion& other) + : m_set(other.m_set) + , m_expansions(other.m_expansions) + { + } + + Expansion(Expansion&& other) + : m_set(other.m_set) + , m_expansions(other.m_expansions) + { + } + + ~Expansion() + { static_for<0, dim-1>::apply([this](const auto d) { - std::get(m_children_traversers).reserve(2*m_expansions); - }); + using Work = MemoryPool< typename Set::template traverser_t< d > >; + + auto& work = Work::getInstance(); + + for (auto& offset_range : std::get(m_work_offsetRanges)) + { + work.freeChunk(offset_range); + } + }); } inline std::size_t level_impl() const @@ -115,32 +134,42 @@ namespace samurai } else { - auto& children_traversers = std::get(m_children_traversers); + using Work = MemoryPool< typename Set::template traverser_t >; + using WorkSize = typename Work::Size; - children_traversers.clear(); + Work& work = Work::getInstance(); + + auto& offsetRange = std::get(m_work_offsetRanges); + + const auto set_traversers_offsets = work.requestChunk( WorkSize(2*(m_expansions[d+1] + 1)) ); + auto end_offset = set_traversers_offsets.first; xt::xtensor_fixed> tmp_index(index); for (value_t width=0; width!=m_expansions[d+1]+1; ++width) { tmp_index[d+1] = index[d+1] + width; - children_traversers.push_back(m_set.get_traverser(tmp_index, d_ic)); - if (children_traversers.back().is_empty()) { children_traversers.pop_back(); } + std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); + if (work.at(end_offset).is_empty()) { std::destroy_at(work.getPtr(end_offset)); } + else { ++end_offset; } tmp_index[d+1] = index[d+1] - width; - children_traversers.push_back(m_set.get_traverser(tmp_index, d_ic)); - if (children_traversers.back().is_empty()) { children_traversers.pop_back(); } + std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); + if (work.at(end_offset).is_empty()) { std::destroy_at(work.getPtr(end_offset)); } + else { ++end_offset; } } - return traverser_t(children_traversers.begin(), children_traversers.end(), m_expansions[d]); + offsetRange.push_back(set_traversers_offsets); + + return traverser_t(set_traversers_offsets.first, end_offset, m_expansions[d]); } } private: - Set m_set; - expansion_t m_expansions; + Set m_set; + expansion_t m_expansions; - mutable ChildrenTraversers m_children_traversers; + mutable OffsetRangeWork m_work_offsetRanges; }; template diff --git a/include/samurai/subset/memory_pool.hpp b/include/samurai/subset/memory_pool.hpp index 4c296d415..f342a3ac9 100644 --- a/include/samurai/subset/memory_pool.hpp +++ b/include/samurai/subset/memory_pool.hpp @@ -24,10 +24,18 @@ class MemoryPool using const_Reference = const Element&; using Distance = typename AllocatorTraits::difference_type; using Size = typename AllocatorTraits::size_type; - using OffsetRange = std::ranges::iota_view; + //~ using OffsetRange = std::ranges::iota_view; static_assert(std::is_move_constructible::value or std::is_trivially_copyable::value); + struct OffsetRange + { + Distance first; + Distance bound; + + inline Size size() const { return Size(bound - first); } + }; + struct Chunk { Distance offset; @@ -176,7 +184,7 @@ auto MemoryPool::freeChunk(const OffsetRange offsets) -> voi { const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), std::end(m_chunks), [&offsets](const Chunk& chunk) -> bool { - return (not chunk.isFree) and chunk.offset == offsets[0] and chunk.size == offsets.size(); + return (not chunk.isFree) and chunk.offset == offsets.first and chunk.size == offsets.size(); }); assert(chunkIt != std::end(m_chunks)); diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 8a6ce0ad0..0042852c2 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -38,10 +38,7 @@ namespace samurai using child_traverser_t = typename Set::template traverser_t; template - using child_traverser_offset_range_t = typename MemoryPool< child_traverser_t >::OffsetRange; - - template - using array_of_child_traverser_offset_range_t = std::vector< child_traverser_offset_range_t >; + using array_of_child_traverser_offset_range_t = std::vector< typename MemoryPool< child_traverser_t >::OffsetRange >; using Type = std::tuple< array_of_child_traverser_offset_range_t... >; }; @@ -135,8 +132,7 @@ namespace samurai if constexpr (d != dim - 1) { const auto set_traversers_offsets = work.requestChunk( 1 << m_shift ); - - auto end_offset = set_traversers_offsets[0]; + auto end_offset = set_traversers_offsets.first; const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; @@ -146,31 +142,32 @@ namespace samurai for (index[d] = ymin; index[d] != ymax; ++index[d]) { std::construct_at(work.getPtr(end_offset), m_set.get_traverser(index, d_ic)); - ++end_offset; + if (work.at(end_offset).is_empty()) { std::destroy_at(work.getPtr(end_offset)); } + else { ++end_offset; } } offsetRange.push_back(set_traversers_offsets); - return traverser_t(set_traversers_offsets[0], end_offset, m_shift); + return traverser_t(set_traversers_offsets.first, end_offset, m_shift); } else { const auto set_traversers_offsets = work.requestChunk( 1 ); - std::construct_at(work.getPtr(set_traversers_offsets[0]), m_set.get_traverser(_index << m_shift, d_ic)); + std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index << m_shift, d_ic)); offsetRange.push_back(set_traversers_offsets); - return traverser_t(set_traversers_offsets[0], m_projectionType, m_shift); + return traverser_t(set_traversers_offsets.first, m_projectionType, m_shift); } } else { const auto set_traversers_offsets = work.requestChunk( 1 ); - std::construct_at(work.getPtr(set_traversers_offsets[0]), m_set.get_traverser(_index >> m_shift, d_ic)); + std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index >> m_shift, d_ic)); offsetRange.push_back(set_traversers_offsets); - return traverser_t(set_traversers_offsets[0], m_projectionType, m_shift); + return traverser_t(set_traversers_offsets.first, m_projectionType, m_shift); } } diff --git a/include/samurai/subset/traversers/expansion_traverser.hpp b/include/samurai/subset/traversers/expansion_traverser.hpp index 4b1c96fdf..14aa11707 100644 --- a/include/samurai/subset/traversers/expansion_traverser.hpp +++ b/include/samurai/subset/traversers/expansion_traverser.hpp @@ -27,10 +27,12 @@ namespace samurai public: SAMURAI_SET_TRAVERSER_TYPEDEFS - using SetTraverserIterator = typename std::vector::iterator; + using SetTraverserIterator = typename std::vector::iterator; + using SetTraverserOffsetRange = MemoryPool::OffsetRange; + using SetTraverserOffset = MemoryPool::Distance; - ExpansionTraverser(SetTraverserIterator begin_set_traverser, SetTraverserIterator end_set_traverser, const value_t expansion) - : m_set_traversers(begin_set_traverser, end_set_traverser) + ExpansionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset bound_set_traverser_offset, const value_t expansion) + : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) , m_expansion(expansion) { assert(m_expansion > 0); @@ -43,12 +45,15 @@ namespace samurai } inline void next_interval_impl() - { + { + auto& memory_pool = MemoryPool::getInstance(); + m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start - for (const SetTraverser& set_traverser : m_set_traversers) + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { + const SetTraverser& set_traverser = memory_pool.at(offset); if (!set_traverser.is_empty() && (set_traverser.current_interval().start - m_expansion < m_current_interval.start)) { m_current_interval.start = set_traverser.current_interval().start - m_expansion; @@ -62,16 +67,18 @@ namespace samurai { is_done = true; // advance set traverses that are behind current interval - for (SetTraverser& set_traverser : m_set_traversers) + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { + SetTraverser& set_traverser = memory_pool.at(offset); while (!set_traverser.is_empty() && set_traverser.current_interval().end + m_expansion <= m_current_interval.end) { set_traverser.next_interval(); } } // try to find a new end - for (const SetTraverser& set_traverser : m_set_traversers) + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { + const SetTraverser& set_traverser = memory_pool.at(offset); // there is an overlap if (!set_traverser.is_empty() && set_traverser.current_interval().start - m_expansion <= m_current_interval.end) { @@ -88,7 +95,7 @@ namespace samurai } private: - std::span m_set_traversers; + SetTraverserOffsetRange m_set_traverser_offsets; value_t m_expansion; interval_t m_current_interval; bool m_isEmpty; diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 2266250b1..ceec31304 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -31,7 +31,6 @@ namespace samurai class ProjectionTraverser : public SetTraverserBase> { using Self = ProjectionTraverser; - //~ using SetTraverserIterator = typename std::vector::iterator; using SetTraverserOffsetRange = MemoryPool::OffsetRange; using SetTraverserOffset = MemoryPool::Distance; @@ -45,30 +44,32 @@ namespace samurai , m_projectionType(projectionType) , m_shift(shift) , m_isEmpty(MemoryPool::getInstance().at(set_traverser_offset).is_empty()) - { - const auto set_traversers = get_set_traversers_view(); + { + auto& memory_pool = MemoryPool::getInstance(); if (!m_isEmpty) { + SetTraverser& set_traverser = memory_pool.at(set_traverser_offset); + if (m_projectionType == ProjectionType::COARSEN) { - m_current_interval.start = coarsen_start(set_traversers[0].current_interval()); - m_current_interval.end = coarsen_end(set_traversers[0].current_interval()); + m_current_interval.start = coarsen_start(set_traverser.current_interval()); + m_current_interval.end = coarsen_end(set_traverser.current_interval()); - set_traversers[0].next_interval(); + set_traverser.next_interval(); // when coarsening, two disjoint intervals may be merged. // we need to check if the next_interval overlaps - for (; !set_traversers[0].is_empty() && coarsen_start(set_traversers[0].current_interval()) <= m_current_interval.end; - set_traversers[0].next_interval()) + for (; !set_traverser.is_empty() && coarsen_start(set_traverser.current_interval()) <= m_current_interval.end; + set_traverser.next_interval()) { - m_current_interval.end = coarsen_end(set_traversers[0].current_interval()); + m_current_interval.end = coarsen_end(set_traverser.current_interval()); } } else { - m_current_interval.start = set_traversers[0].current_interval().start << shift; - m_current_interval.end = set_traversers[0].current_interval().end << shift; + m_current_interval.start = set_traverser.current_interval().start << shift; + m_current_interval.end = set_traverser.current_interval().end << shift; } } } @@ -76,8 +77,8 @@ namespace samurai /* * This constructor only works for coarsening */ - ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset last_set_traverser_offset, const std::size_t shift) - : m_set_traverser_offsets(first_set_traverser_offset, last_set_traverser_offset) + ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset bound_set_traverser_offset, const std::size_t shift) + : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) { @@ -91,20 +92,20 @@ namespace samurai inline void next_interval_impl() { - const auto set_traversers = get_set_traversers_view(); - if (m_projectionType == ProjectionType::COARSEN) { next_interval_coarsen(); } else { - set_traversers[0].next_interval(); - m_isEmpty = set_traversers[0].is_empty(); + SetTraverser& set_traverser = MemoryPool::getInstance().at(m_set_traverser_offsets.first); + + set_traverser.next_interval(); + m_isEmpty = set_traverser.is_empty(); if (!m_isEmpty) { - m_current_interval.start = set_traversers[0].current_interval().start << m_shift; - m_current_interval.end = set_traversers[0].current_interval().end << m_shift; + m_current_interval.start = set_traverser.current_interval().start << m_shift; + m_current_interval.end = set_traverser.current_interval().end << m_shift; } } } @@ -116,22 +117,16 @@ namespace samurai private: - inline auto get_set_traversers_view() - { - return m_set_traverser_offsets | std::views::transform([&pool = MemoryPool::getInstance()](const SetTraverserOffset& offset) -> SetTraverser& - { - return pool.at(offset); - }); - } - inline void next_interval_coarsen() { - const auto set_traversers = get_set_traversers_view(); + auto& memory_pool = MemoryPool::getInstance(); m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift - for (const SetTraverser& set_traverser : set_traversers) + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { + const SetTraverser& set_traverser = memory_pool.at(offset); + if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) < m_current_interval.start)) { m_current_interval.start = coarsen_start(set_traverser.current_interval()); @@ -145,16 +140,20 @@ namespace samurai { is_done = true; // advance set traverses that are behind current interval - for (SetTraverser& set_traverser : set_traversers) + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { + SetTraverser& set_traverser = memory_pool.at(offset); + while (!set_traverser.is_empty() && (coarsen_end(set_traverser.current_interval()) <= m_current_interval.end)) { set_traverser.next_interval(); } } // try to find a new end - for (const SetTraverser& set_traverser : set_traversers) + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { + const SetTraverser& set_traverser = memory_pool.at(offset); + // there is an overlap if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) <= m_current_interval.end)) { @@ -176,11 +175,11 @@ namespace samurai return ((interval.end - 1) >> m_shift) + 1; } - SetTraverserOffsetRange m_set_traverser_offsets; - ProjectionType m_projectionType; - std::size_t m_shift; - interval_t m_current_interval; - bool m_isEmpty; + SetTraverserOffsetRange m_set_traverser_offsets; + ProjectionType m_projectionType; + std::size_t m_shift; + interval_t m_current_interval; + bool m_isEmpty; }; } // namespace samurai From 2982c884f4ba4765ac64aa8006060d3e6ac453eb Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 16:51:54 +0200 Subject: [PATCH 08/28] with pre-commit --- .../linear_convection_obstacle.cpp | 2 +- include/samurai/algorithm/update.hpp | 12 +- include/samurai/level_cell_array.hpp | 2 +- include/samurai/subset/apply.hpp | 4 +- include/samurai/subset/box_view.hpp | 6 +- include/samurai/subset/contraction.hpp | 4 +- include/samurai/subset/expansion.hpp | 293 +++++++------ include/samurai/subset/lca_view.hpp | 44 +- include/samurai/subset/memory_pool.hpp | 412 ++++++++++-------- include/samurai/subset/nary_set_operator.hpp | 2 +- include/samurai/subset/projection.hpp | 162 +++---- include/samurai/subset/set_base.hpp | 56 +-- .../traversers/contraction_traverser.hpp | 8 +- .../subset/traversers/expansion_traverser.hpp | 173 ++++---- .../last_dim_expansion_traverser.hpp | 107 ++--- .../traversers/projection_traverser.hpp | 60 +-- tests/test_subset.cpp | 252 +++++------ 17 files changed, 855 insertions(+), 744 deletions(-) diff --git a/demos/FiniteVolume/linear_convection_obstacle.cpp b/demos/FiniteVolume/linear_convection_obstacle.cpp index 57f85a95c..f8329ed83 100644 --- a/demos/FiniteVolume/linear_convection_obstacle.cpp +++ b/demos/FiniteVolume/linear_convection_obstacle.cpp @@ -137,7 +137,7 @@ int main(int argc, char* argv[]) double t = 0; //~ while (t != Tf) - for (int ite=0; ite!=23; ++ite) + for (int ite = 0; ite != 23; ++ite) { // Move to next timestep t += dt; diff --git a/include/samurai/algorithm/update.hpp b/include/samurai/algorithm/update.hpp index 9a6ce5b2b..0a3fba92a 100644 --- a/include/samurai/algorithm/update.hpp +++ b/include/samurai/algorithm/update.hpp @@ -135,10 +135,14 @@ namespace samurai auto bc_ghosts_in_other_directions = domain_boundary_outer_layer(mesh, proj_level, n_bc_ghosts); auto projection_ghosts_no_bc_ghosts = difference(projection_ghosts, bc_ghosts_in_other_directions); - - const auto lca_projection_ghosts = projection_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); - const auto lca_projection_ghosts_no_bc_ghosts = projection_ghosts_no_bc_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); - const auto lca_domain = domain.to_lca(bc_ghosts_in_other_directions.origin_point(), bc_ghosts_in_other_directions.scaling_factor()); + + const auto lca_projection_ghosts = projection_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), + bc_ghosts_in_other_directions.scaling_factor()); + const auto lca_projection_ghosts_no_bc_ghosts = projection_ghosts_no_bc_ghosts.to_lca( + bc_ghosts_in_other_directions.origin_point(), + bc_ghosts_in_other_directions.scaling_factor()); + const auto lca_domain = domain.to_lca(bc_ghosts_in_other_directions.origin_point(), + bc_ghosts_in_other_directions.scaling_factor()); project_bc(projection_ghosts_no_bc_ghosts, proj_level, direction, layer, field); } diff --git a/include/samurai/level_cell_array.hpp b/include/samurai/level_cell_array.hpp index 1396a115c..2bccd81eb 100644 --- a/include/samurai/level_cell_array.hpp +++ b/include/samurai/level_cell_array.hpp @@ -99,7 +99,7 @@ namespace samurai template LevelCellArray(const SetBase& set); - + template LevelCellArray(const SetBase& set, const coords_t& origin_point, const double scaling_factor); diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index c78176ea6..eccb563be 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -16,9 +16,9 @@ namespace samurai using current_interval_t = typename traverser_t::current_interval_t; for (traverser_t traverser = set.get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) - { + { current_interval_t interval = traverser.current_interval(); - + if constexpr (d == 0) { func(interval, index); diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 148bfa34a..924392dc7 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -57,9 +57,9 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const { - return (m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]) - ? traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]) - : traverser_t(0, 0); + return (m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]) + ? traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]) + : traverser_t(0, 0); } private: diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 6cec5c8b4..83ae68b3c 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -107,8 +107,8 @@ namespace samurai auto contract(const Set& set, const typename Contraction>::value_t contraction, const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this - // more readable, - // perhaps a traits... + // more readable, + // perhaps a traits... { return Contraction(self(set), contraction, do_contraction); } diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 1908e1008..7631b1d7b 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -9,8 +9,8 @@ namespace samurai { - - template + + template class Expansion; template @@ -19,98 +19,100 @@ namespace samurai static_assert(IsSet::value); template - using traverser_t = std::conditional_t> - , ExpansionTraverser>>; + using traverser_t = std::conditional_t>, + ExpansionTraverser>>; static constexpr std::size_t dim = Set::dim; }; - + namespace detail { - template - struct ExpansionWork; - - template - struct ExpansionWork> - { - template - using child_traverser_t = typename Set::template traverser_t; - - template - using array_of_child_traverser_offset_range_t = std::vector< typename MemoryPool< child_traverser_t >::OffsetRange >; - - using Type = std::tuple< array_of_child_traverser_offset_range_t... >; - - static_assert(std::tuple_size::value == Set::dim-1); - }; - - } // namespace detail - - template + template + struct ExpansionWork; + + template + struct ExpansionWork> + { + template + using child_traverser_t = typename Set::template traverser_t; + + template + using array_of_child_traverser_offset_range_t = std::vector>::OffsetRange>; + + using Type = std::tuple...>; + + static_assert(std::tuple_size::value == Set::dim - 1); + }; + + } // namespace detail + + template class Expansion : public SetBase> { - using Self = Expansion; - using OffsetRangeWork = detail::ExpansionWork< Set, std::make_index_sequence >::Type; + using Self = Expansion; + using OffsetRangeWork = detail::ExpansionWork>::Type; + public: SAMURAI_SET_TYPEDEFS SAMURAI_SET_CONSTEXPRS - - using expansion_t = std::array; + + using expansion_t = std::array; using do_expansion_t = std::array; - + Expansion(const Set& set, const expansion_t& expansions) - : m_set(set) - , m_expansions(expansions) - { - } - + : m_set(set) + , m_expansions(expansions) + { + } + Expansion(const Set& set, const value_t expansion) - : m_set(set) - { - m_expansions.fill(expansion); - } - + : m_set(set) + { + m_expansions.fill(expansion); + } + Expansion(const Set& set, const value_t expansion, const do_expansion_t& do_expansion) - : m_set(set) - { - for (std::size_t i = 0; i != m_expansions.size(); ++i) + : m_set(set) + { + for (std::size_t i = 0; i != m_expansions.size(); ++i) { m_expansions[i] = expansion * do_expansion[i]; } - } - - // we need to define a custom copy and move constructor because - // we do not want to copy m_work_offsetRanges - Expansion(const Expansion& other) - : m_set(other.m_set) - , m_expansions(other.m_expansions) - { - } - - Expansion(Expansion&& other) - : m_set(other.m_set) - , m_expansions(other.m_expansions) - { - } - - ~Expansion() - { - static_for<0, dim-1>::apply([this](const auto d) - { - using Work = MemoryPool< typename Set::template traverser_t< d > >; - - auto& work = Work::getInstance(); - - for (auto& offset_range : std::get(m_work_offsetRanges)) - { - work.freeChunk(offset_range); - } - }); - } - - inline std::size_t level_impl() const + } + + // we need to define a custom copy and move constructor because + // we do not want to copy m_work_offsetRanges + Expansion(const Expansion& other) + : m_set(other.m_set) + , m_expansions(other.m_expansions) + { + } + + Expansion(Expansion&& other) + : m_set(other.m_set) + , m_expansions(other.m_expansions) + { + } + + ~Expansion() + { + static_for<0, dim - 1>::apply( + [this](const auto d) + { + using Work = MemoryPool>; + + auto& work = Work::getInstance(); + + for (auto& offset_range : std::get(m_work_offsetRanges)) + { + work.freeChunk(offset_range); + } + }); + } + + inline std::size_t level_impl() const { return m_set.level(); } @@ -128,66 +130,81 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - if constexpr (d == dim-1) - { - return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); - } - else - { - using Work = MemoryPool< typename Set::template traverser_t >; - using WorkSize = typename Work::Size; - - Work& work = Work::getInstance(); - - auto& offsetRange = std::get(m_work_offsetRanges); - - const auto set_traversers_offsets = work.requestChunk( WorkSize(2*(m_expansions[d+1] + 1)) ); - auto end_offset = set_traversers_offsets.first; - - xt::xtensor_fixed> tmp_index(index); - - for (value_t width=0; width!=m_expansions[d+1]+1; ++width) - { - tmp_index[d+1] = index[d+1] + width; - std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); - if (work.at(end_offset).is_empty()) { std::destroy_at(work.getPtr(end_offset)); } - else { ++end_offset; } - - tmp_index[d+1] = index[d+1] - width; - std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); - if (work.at(end_offset).is_empty()) { std::destroy_at(work.getPtr(end_offset)); } - else { ++end_offset; } - } - - offsetRange.push_back(set_traversers_offsets); - - return traverser_t(set_traversers_offsets.first, end_offset, m_expansions[d]); - } - } - - private: - Set m_set; - expansion_t m_expansions; - - mutable OffsetRangeWork m_work_offsetRanges; - }; - - template - auto expand(const Set& set, const typename Contraction>::contraction_t& expansions) - { - return Expansion(self(set), expansions); - } - - template - auto expand(const Set& set, const typename Contraction>::value_t expansion) - { - return Expansion(self(set), expansion); - } - - template - auto expand(const Set& set, const typename Contraction>::value_t expansion, const typename Contraction>::do_expansion_t& do_expansion) - { - return Expansion(self(set), expansion, do_expansion); - } - + if constexpr (d == dim - 1) + { + return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); + } + else + { + using Work = MemoryPool>; + using WorkSize = typename Work::Size; + + Work& work = Work::getInstance(); + + auto& offsetRange = std::get(m_work_offsetRanges); + + const auto set_traversers_offsets = work.requestChunk(WorkSize(2 * (m_expansions[d + 1] + 1))); + auto end_offset = set_traversers_offsets.first; + + xt::xtensor_fixed> tmp_index(index); + + for (value_t width = 0; width != m_expansions[d + 1] + 1; ++width) + { + tmp_index[d + 1] = index[d + 1] + width; + std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); + if (work.at(end_offset).is_empty()) + { + std::destroy_at(work.getPtr(end_offset)); + } + else + { + ++end_offset; + } + + tmp_index[d + 1] = index[d + 1] - width; + std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); + if (work.at(end_offset).is_empty()) + { + std::destroy_at(work.getPtr(end_offset)); + } + else + { + ++end_offset; + } + } + + offsetRange.push_back(set_traversers_offsets); + + return traverser_t(set_traversers_offsets.first, end_offset, m_expansions[d]); + } + } + + private: + + Set m_set; + expansion_t m_expansions; + + mutable OffsetRangeWork m_work_offsetRanges; + }; + + template + auto expand(const Set& set, const typename Contraction>::contraction_t& expansions) + { + return Expansion(self(set), expansions); + } + + template + auto expand(const Set& set, const typename Contraction>::value_t expansion) + { + return Expansion(self(set), expansion); + } + + template + auto expand(const Set& set, + const typename Contraction>::value_t expansion, + const typename Contraction>::do_expansion_t& do_expansion) + { + return Expansion(self(set), expansion, do_expansion); + } + } // namespace samurai diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index aa936cf6b..f7904db75 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -32,7 +32,7 @@ namespace samurai SAMURAI_SET_TYPEDEFS SAMURAI_SET_CONSTEXPRS - + using const_interval_iterator = typename std::vector::const_iterator; LCAView(const LCA& lca) @@ -58,11 +58,19 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - return get_traverser_impl_detail(index, m_lca[dim-1].cbegin(), m_lca[dim-1].cend(), d_ic, std::integral_constant{}); + return get_traverser_impl_detail(index, + m_lca[dim - 1].cbegin(), + m_lca[dim - 1].cend(), + d_ic, + std::integral_constant{}); } - + template - inline traverser_t get_traverser_impl_detail(const index_t& index, const_interval_iterator begin_y_interval, const_interval_iterator end_y_interval, std::integral_constant d_ic, std::integral_constant dCur_ic) const + inline traverser_t get_traverser_impl_detail(const index_t& index, + const_interval_iterator begin_y_interval, + const_interval_iterator end_y_interval, + std::integral_constant d_ic, + std::integral_constant dCur_ic) const { if constexpr (dCur != dim - 1) { @@ -78,7 +86,7 @@ namespace samurai if (y_interval_it != end_y_interval) { const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); - + const_interval_iterator begin_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]); const_interval_iterator end_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1]); @@ -94,19 +102,23 @@ namespace samurai return get_traverser_impl_detail_wrapper(index, m_lca[dCur].cbegin(), m_lca[dCur].cend(), d_ic, dCur_ic); } } - + template - inline traverser_t get_traverser_impl_detail_wrapper(const index_t& index, const_interval_iterator begin_x_interval, const_interval_iterator end_x_interval, std::integral_constant d_ic, std::integral_constant) const + inline traverser_t get_traverser_impl_detail_wrapper(const index_t& index, + const_interval_iterator begin_x_interval, + const_interval_iterator end_x_interval, + std::integral_constant d_ic, + std::integral_constant) const { - if constexpr (d == dCur) - { - return traverser_t(begin_x_interval, end_x_interval); - } - else - { - return get_traverser_impl_detail(index, begin_x_interval, end_x_interval, d_ic, std::integral_constant{}); - } - } + if constexpr (d == dCur) + { + return traverser_t(begin_x_interval, end_x_interval); + } + else + { + return get_traverser_impl_detail(index, begin_x_interval, end_x_interval, d_ic, std::integral_constant{}); + } + } private: diff --git a/include/samurai/subset/memory_pool.hpp b/include/samurai/subset/memory_pool.hpp index f342a3ac9..3e86f84f5 100644 --- a/include/samurai/subset/memory_pool.hpp +++ b/include/samurai/subset/memory_pool.hpp @@ -3,19 +3,20 @@ #pragma once -#include -#include -#include #include +#include +#include #include +#include #include -template> +template > class MemoryPool { -public: - using Allocator = typename std::allocator_traits::template rebind_alloc; + public: + + using Allocator = typename std::allocator_traits::template rebind_alloc; using AllocatorTraits = std::allocator_traits; using Element = typename AllocatorTraits::value_type; using Pointer = typename AllocatorTraits::pointer; @@ -24,196 +25,249 @@ class MemoryPool using const_Reference = const Element&; using Distance = typename AllocatorTraits::difference_type; using Size = typename AllocatorTraits::size_type; - //~ using OffsetRange = std::ranges::iota_view; - - static_assert(std::is_move_constructible::value or std::is_trivially_copyable::value); - - struct OffsetRange - { - Distance first; - Distance bound; - - inline Size size() const { return Size(bound - first); } - }; - - struct Chunk - { - Distance offset; - Size size; - bool isFree; - - friend bool operator<(const Chunk& lhs, const Chunk& rhs) { return lhs.offset < rhs.offset; } - }; + //~ using OffsetRange = std::ranges::iota_view; + + static_assert(std::is_move_constructible::value or std::is_trivially_copyable::value); + + struct OffsetRange + { + Distance first; + Distance bound; + + inline Size size() const + { + return Size(bound - first); + } + }; + + struct Chunk + { + Distance offset; + Size size; + bool isFree; + + friend bool operator<(const Chunk& lhs, const Chunk& rhs) + { + return lhs.offset < rhs.offset; + } + }; using ChunkIterator = typename std::vector::iterator; - - MemoryPool(const MemoryPool&) = delete; + + MemoryPool(const MemoryPool&) = delete; MemoryPool& operator=(const MemoryPool&) = delete; - - ~MemoryPool(); - + + ~MemoryPool(); + OffsetRange requestChunk(const Size chunkSize); - + void freeChunk(const OffsetRange offsets); - - Pointer getPtr(const Distance offset) { assert(Size(offset) < m_totalSize); return m_memory + offset; } - const_Pointer getPtr(const Distance offset) const { assert(Size(offset) < m_totalSize); return m_memory + offset; } - - Reference at(const Distance offset) { return *getPtr(offset); } - const_Reference at(const Distance offset) const { return *getPtr(offset); } - - Reference operator[](const Distance offset) { return at(offset); } - const_Reference operator[](const Distance offset) const { return at(offset); } - - Size totalSize() const { return m_totalSize; } - + + Pointer getPtr(const Distance offset) + { + assert(Size(offset) < m_totalSize); + return m_memory + offset; + } + + const_Pointer getPtr(const Distance offset) const + { + assert(Size(offset) < m_totalSize); + return m_memory + offset; + } + + Reference at(const Distance offset) + { + return *getPtr(offset); + } + + const_Reference at(const Distance offset) const + { + return *getPtr(offset); + } + + Reference operator[](const Distance offset) + { + return at(offset); + } + + const_Reference operator[](const Distance offset) const + { + return at(offset); + } + + Size totalSize() const + { + return m_totalSize; + } + static MemoryPool& getInstance(); -private: - MemoryPool() {} - Pointer m_memory = nullptr; - Size m_totalSize = 0; - Allocator m_allocator; + private: + + MemoryPool() + { + } + + Pointer m_memory = nullptr; + Size m_totalSize = 0; + Allocator m_allocator; std::vector m_chunks; }; -template -MemoryPool& MemoryPool::getInstance() +template +MemoryPool& MemoryPool::getInstance() { - static MemoryPool instance; - - return instance; + static MemoryPool instance; + + return instance; } -template -MemoryPool::~MemoryPool() +template +MemoryPool::~MemoryPool() { - assert(std::all_of(std::begin(m_chunks), std::end(m_chunks), [](const Chunk& chunk) -> bool - { - return chunk.isFree; - })); - - m_allocator.deallocate(m_memory, m_totalSize); - - m_memory = nullptr; - m_totalSize = 0; + assert(std::all_of(std::begin(m_chunks), + std::end(m_chunks), + [](const Chunk& chunk) -> bool + { + return chunk.isFree; + })); + + m_allocator.deallocate(m_memory, m_totalSize); + + m_memory = nullptr; + m_totalSize = 0; } -template -auto MemoryPool::requestChunk(const Size chunkSize) -> OffsetRange +template +auto MemoryPool::requestChunk(const Size chunkSize) -> OffsetRange { - const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), std::end(m_chunks), [chunkSize](const Chunk& chunk) -> bool - { - return chunk.isFree and chunk.size >= chunkSize; - }); - - if (chunkIt != std::end(m_chunks)) - { - chunkIt->isFree = false; - const OffsetRange ret(chunkIt->offset, chunkIt->offset + Distance(chunkSize)); - - if (chunkIt->size > chunkSize) - { - // slipt the chunk - const Distance newChunkOffset = chunkIt->offset + Distance(chunkSize); - const Size newChunkSize = chunkIt->size - chunkSize; - - chunkIt->size = chunkSize; - m_chunks.push_back({.offset = newChunkOffset, .size = newChunkSize, .isFree = true}); - } - - return ret; - } - else if (m_memory != nullptr) - { - const Size newTotalSize = std::max(m_totalSize + chunkSize, 2*m_totalSize); - // we need to reallocate a larger buffer - Pointer newMemory = m_allocator.allocate(newTotalSize); - // we need to move all the data from our buffer to the new one - auto usedChunks = m_chunks | std::views::filter([] (const Chunk& chunk) { return not chunk.isFree; }); - - for (const Chunk& chunk : usedChunks) - { - Pointer beginChunk = m_memory + chunk.offset; - Pointer endChunk = beginChunk + chunk.size; - Pointer dstIt = newMemory + chunk.offset; - if constexpr (std::is_trivially_copyable::value) - { - std::copy(beginChunk, endChunk, dstIt); - std::destroy(beginChunk, endChunk); - } - else - { - for (Pointer srcIt=beginChunk; srcIt!=endChunk; ++srcIt, ++dstIt) - { - std::construct_at(dstIt, std::move(*srcIt)); - std::destroy_at(srcIt); - } - } - } - // now we can swap the pointers and free newMemory - std::swap(m_memory, newMemory); - m_allocator.deallocate(newMemory, m_totalSize); - - // now we create a new chunk with the correct size - - m_chunks.push_back({.offset = Distance(m_totalSize), .size = chunkSize, .isFree = false}); - OffsetRange ret(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); - - if (newTotalSize != (m_totalSize + chunkSize)) - { - m_chunks.push_back({.offset = Distance(m_totalSize + chunkSize), .size = Size(newTotalSize - m_totalSize - chunkSize), .isFree = true}); - } - m_totalSize = newTotalSize; - - return ret; - } - else - { - m_memory = m_allocator.allocate(chunkSize); - m_totalSize = chunkSize; - - m_chunks.push_back({.offset = 0, .size = chunkSize, .isFree = false}); - - return OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); - } + const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), + std::end(m_chunks), + [chunkSize](const Chunk& chunk) -> bool + { + return chunk.isFree and chunk.size >= chunkSize; + }); + + if (chunkIt != std::end(m_chunks)) + { + chunkIt->isFree = false; + const OffsetRange ret(chunkIt->offset, chunkIt->offset + Distance(chunkSize)); + + if (chunkIt->size > chunkSize) + { + // slipt the chunk + const Distance newChunkOffset = chunkIt->offset + Distance(chunkSize); + const Size newChunkSize = chunkIt->size - chunkSize; + + chunkIt->size = chunkSize; + m_chunks.push_back({.offset = newChunkOffset, .size = newChunkSize, .isFree = true}); + } + + return ret; + } + else if (m_memory != nullptr) + { + const Size newTotalSize = std::max(m_totalSize + chunkSize, 2 * m_totalSize); + // we need to reallocate a larger buffer + Pointer newMemory = m_allocator.allocate(newTotalSize); + // we need to move all the data from our buffer to the new one + auto usedChunks = m_chunks + | std::views::filter( + [](const Chunk& chunk) + { + return not chunk.isFree; + }); + + for (const Chunk& chunk : usedChunks) + { + Pointer beginChunk = m_memory + chunk.offset; + Pointer endChunk = beginChunk + chunk.size; + Pointer dstIt = newMemory + chunk.offset; + if constexpr (std::is_trivially_copyable::value) + { + std::copy(beginChunk, endChunk, dstIt); + std::destroy(beginChunk, endChunk); + } + else + { + for (Pointer srcIt = beginChunk; srcIt != endChunk; ++srcIt, ++dstIt) + { + std::construct_at(dstIt, std::move(*srcIt)); + std::destroy_at(srcIt); + } + } + } + // now we can swap the pointers and free newMemory + std::swap(m_memory, newMemory); + m_allocator.deallocate(newMemory, m_totalSize); + + // now we create a new chunk with the correct size + + m_chunks.push_back({.offset = Distance(m_totalSize), .size = chunkSize, .isFree = false}); + OffsetRange ret(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); + + if (newTotalSize != (m_totalSize + chunkSize)) + { + m_chunks.push_back( + {.offset = Distance(m_totalSize + chunkSize), .size = Size(newTotalSize - m_totalSize - chunkSize), .isFree = true}); + } + m_totalSize = newTotalSize; + + return ret; + } + else + { + m_memory = m_allocator.allocate(chunkSize); + m_totalSize = chunkSize; + + m_chunks.push_back({.offset = 0, .size = chunkSize, .isFree = false}); + + return OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); + } } -template -auto MemoryPool::freeChunk(const OffsetRange offsets) -> void -{ - const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), std::end(m_chunks), [&offsets](const Chunk& chunk) -> bool - { - return (not chunk.isFree) and chunk.offset == offsets.first and chunk.size == offsets.size(); - }); - - assert(chunkIt != std::end(m_chunks)); - - if (chunkIt != std::end(m_chunks)) - { - chunkIt->isFree = true; - - std::destroy(m_memory + chunkIt->offset, m_memory + chunkIt->offset + chunkIt->size); - - // Coalescing - std::sort(std::begin(m_chunks), std::end(m_chunks)); - - for (ChunkIterator it=std::begin(m_chunks); it!=std::end(m_chunks); ++it) - { - if (it->isFree) - { - for (auto nextIt=std::next(it); nextIt!=std::end(m_chunks) and nextIt->isFree and it->offset + Distance(it->size) == nextIt->offset; ++nextIt) - { - it->size += nextIt->size; - nextIt->size = 0; // mark for removal with std::remove_if - } - } - } - - const ChunkIterator newEnd = std::remove_if(std::begin(m_chunks), std::end(m_chunks), [](const Chunk& chunk) -> bool - { - return chunk.size == 0; - }); - m_chunks.erase(newEnd, std::end(m_chunks)); - } +template +auto MemoryPool::freeChunk(const OffsetRange offsets) -> void +{ + const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), + std::end(m_chunks), + [&offsets](const Chunk& chunk) -> bool + { + return (not chunk.isFree) and chunk.offset == offsets.first + and chunk.size == offsets.size(); + }); + + assert(chunkIt != std::end(m_chunks)); + + if (chunkIt != std::end(m_chunks)) + { + chunkIt->isFree = true; + + std::destroy(m_memory + chunkIt->offset, m_memory + chunkIt->offset + chunkIt->size); + + // Coalescing + std::sort(std::begin(m_chunks), std::end(m_chunks)); + + for (ChunkIterator it = std::begin(m_chunks); it != std::end(m_chunks); ++it) + { + if (it->isFree) + { + for (auto nextIt = std::next(it); + nextIt != std::end(m_chunks) and nextIt->isFree and it->offset + Distance(it->size) == nextIt->offset; + ++nextIt) + { + it->size += nextIt->size; + nextIt->size = 0; // mark for removal with std::remove_if + } + } + } + + const ChunkIterator newEnd = std::remove_if(std::begin(m_chunks), + std::end(m_chunks), + [](const Chunk& chunk) -> bool + { + return chunk.size == 0; + }); + m_chunks.erase(newEnd, std::end(m_chunks)); + } } diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index fef64f6d8..c14681baa 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -116,7 +116,7 @@ namespace samurai inline bool empty_impl() const { - return Base::empty_default_impl(); + return Base::empty_default_impl(); } template diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 0042852c2..3bf3ce711 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -5,8 +5,8 @@ #include "../samurai_config.hpp" #include "../static_algorithm.hpp" -#include "set_base.hpp" #include "memory_pool.hpp" +#include "set_base.hpp" #include "traversers/projection_traverser.hpp" namespace samurai @@ -21,34 +21,35 @@ namespace samurai static_assert(IsSet::value); template - using traverser_t = ProjectionTraverser< typename Set::template traverser_t >; + using traverser_t = ProjectionTraverser>; static constexpr std::size_t dim = Set::dim; }; - + namespace detail { - template - struct ProjectionWork; - - template - struct ProjectionWork> - { - template - using child_traverser_t = typename Set::template traverser_t; - - template - using array_of_child_traverser_offset_range_t = std::vector< typename MemoryPool< child_traverser_t >::OffsetRange >; - - using Type = std::tuple< array_of_child_traverser_offset_range_t... >; - }; - } // namespace detail + template + struct ProjectionWork; + + template + struct ProjectionWork> + { + template + using child_traverser_t = typename Set::template traverser_t; + + template + using array_of_child_traverser_offset_range_t = std::vector>::OffsetRange>; + + using Type = std::tuple...>; + }; + } // namespace detail template class Projection : public SetBase> { - using Self = Projection; - using OffsetRangeWork = detail::ProjectionWork< Set, std::make_index_sequence >::Type; + using Self = Projection; + using OffsetRangeWork = detail::ProjectionWork>::Type; + public: SAMURAI_SET_TYPEDEFS @@ -70,38 +71,39 @@ namespace samurai } } - // we need to define a custom copy and move constructor because - // we do not want to copy m_work_offsetRanges - Projection(const Projection& other) - : m_set(other.m_set) - , m_level(other.m_level) - , m_projectionType(other.m_projectionType) - , m_shift(other.m_shift) - { - } - - Projection(Projection&& other) - : m_set(std::move(other.m_set)) - , m_level(std::move(other.m_level)) - , m_projectionType(std::move(other.m_projectionType)) - , m_shift(std::move(other.m_shift)) - { - } - - ~Projection() - { - static_for<0, dim>::apply([this](const auto d) - { - using Work = MemoryPool< typename Set::template traverser_t< d > >; - - auto& work = Work::getInstance(); - - for (auto& offset_range : std::get(m_work_offsetRanges)) - { - work.freeChunk(offset_range); - } - }); - } + // we need to define a custom copy and move constructor because + // we do not want to copy m_work_offsetRanges + Projection(const Projection& other) + : m_set(other.m_set) + , m_level(other.m_level) + , m_projectionType(other.m_projectionType) + , m_shift(other.m_shift) + { + } + + Projection(Projection&& other) + : m_set(std::move(other.m_set)) + , m_level(std::move(other.m_level)) + , m_projectionType(std::move(other.m_projectionType)) + , m_shift(std::move(other.m_shift)) + { + } + + ~Projection() + { + static_for<0, dim>::apply( + [this](const auto d) + { + using Work = MemoryPool>; + + auto& work = Work::getInstance(); + + for (auto& offset_range : std::get(m_work_offsetRanges)) + { + work.freeChunk(offset_range); + } + }); + } inline std::size_t level_impl() const { @@ -121,19 +123,19 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const { - using Work = MemoryPool< typename Set::template traverser_t >; - - Work& work = Work::getInstance(); - - auto& offsetRange = std::get(m_work_offsetRanges); - + using Work = MemoryPool>; + + Work& work = Work::getInstance(); + + auto& offsetRange = std::get(m_work_offsetRanges); + if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != dim - 1) { - const auto set_traversers_offsets = work.requestChunk( 1 << m_shift ); - auto end_offset = set_traversers_offsets.first; - + const auto set_traversers_offsets = work.requestChunk(1 << m_shift); + auto end_offset = set_traversers_offsets.first; + const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; @@ -141,32 +143,38 @@ namespace samurai for (index[d] = ymin; index[d] != ymax; ++index[d]) { - std::construct_at(work.getPtr(end_offset), m_set.get_traverser(index, d_ic)); - if (work.at(end_offset).is_empty()) { std::destroy_at(work.getPtr(end_offset)); } - else { ++end_offset; } + std::construct_at(work.getPtr(end_offset), m_set.get_traverser(index, d_ic)); + if (work.at(end_offset).is_empty()) + { + std::destroy_at(work.getPtr(end_offset)); + } + else + { + ++end_offset; + } } - + offsetRange.push_back(set_traversers_offsets); - + return traverser_t(set_traversers_offsets.first, end_offset, m_shift); } else { - const auto set_traversers_offsets = work.requestChunk( 1 ); - std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index << m_shift, d_ic)); - - offsetRange.push_back(set_traversers_offsets); - + const auto set_traversers_offsets = work.requestChunk(1); + std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index << m_shift, d_ic)); + + offsetRange.push_back(set_traversers_offsets); + return traverser_t(set_traversers_offsets.first, m_projectionType, m_shift); } } else { - const auto set_traversers_offsets = work.requestChunk( 1 ); - std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index >> m_shift, d_ic)); - - offsetRange.push_back(set_traversers_offsets); - + const auto set_traversers_offsets = work.requestChunk(1); + std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index >> m_shift, d_ic)); + + offsetRange.push_back(set_traversers_offsets); + return traverser_t(set_traversers_offsets.first, m_projectionType, m_shift); } } @@ -177,7 +185,7 @@ namespace samurai std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; - + mutable OffsetRangeWork m_work_offsetRanges; }; diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index dbea148c1..e390726d8 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -42,7 +42,7 @@ namespace samurai using traverser_t = typename DerivedTraits::template traverser_t; using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; - + using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; @@ -98,49 +98,51 @@ namespace samurai }; apply(derived_cast(), func); } - + to_lca_t to_lca() const { - return to_lca_t(*this); - } - - to_lca_t to_lca(const to_lca_coord_t& origin_point, const double scaling_factor) const + return to_lca_t(*this); + } + + to_lca_t to_lca(const to_lca_coord_t& origin_point, const double scaling_factor) const { - return to_lca_t(*this, origin_point, scaling_factor); - } - protected: - inline bool empty_default_impl() const + return to_lca_t(*this, origin_point, scaling_factor); + } + + protected: + + inline bool empty_default_impl() const { xt::xtensor_fixed> index; - return empty_default_impl_rec(index, std::integral_constant{}); + return empty_default_impl_rec(index, std::integral_constant{}); } - - template + + template bool empty_default_impl_rec(index_t& index, std::integral_constant d_ic) const { - using current_interval_t = typename traverser_t::current_interval_t; - - for (traverser_t traverser = get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) - { - current_interval_t interval = traverser.current_interval(); - - if constexpr (d == 0) + using current_interval_t = typename traverser_t::current_interval_t; + + for (traverser_t traverser = get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) + { + current_interval_t interval = traverser.current_interval(); + + if constexpr (d == 0) { return false; } else { - for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) + for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) { if (not empty_default_impl_rec(index, std::integral_constant{})) { - return false; - } + return false; + } } - } - } - return true; - } + } + } + return true; + } }; #define SAMURAI_SET_TYPEDEFS \ diff --git a/include/samurai/subset/traversers/contraction_traverser.hpp b/include/samurai/subset/traversers/contraction_traverser.hpp index b2fbc7a27..8d9876f8d 100644 --- a/include/samurai/subset/traversers/contraction_traverser.hpp +++ b/include/samurai/subset/traversers/contraction_traverser.hpp @@ -56,13 +56,13 @@ namespace samurai private: - inline void advance_to_next_valid_interval() - { - while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) + inline void advance_to_next_valid_interval() + { + while (!m_set_traverser.is_empty() && m_set_traverser.current_interval().size() <= size_t(2 * m_contraction)) { m_set_traverser.next_interval(); } - } + } SetTraverser m_set_traverser; value_t m_contraction; diff --git a/include/samurai/subset/traversers/expansion_traverser.hpp b/include/samurai/subset/traversers/expansion_traverser.hpp index 14aa11707..14edcbf6e 100644 --- a/include/samurai/subset/traversers/expansion_traverser.hpp +++ b/include/samurai/subset/traversers/expansion_traverser.hpp @@ -8,8 +8,8 @@ namespace samurai { - template - class ExpansionTraverser; + template + class ExpansionTraverser; template struct SetTraverserTraits> @@ -19,86 +19,91 @@ namespace samurai using interval_t = typename SetTraverserTraits::interval_t; using current_interval_t = const interval_t&; }; - - template - class ExpansionTraverser : public SetTraverserBase< ExpansionTraverser > - { - using Self = ExpansionTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - using SetTraverserIterator = typename std::vector::iterator; - using SetTraverserOffsetRange = MemoryPool::OffsetRange; - using SetTraverserOffset = MemoryPool::Distance; - - ExpansionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset bound_set_traverser_offset, const value_t expansion) - : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) - , m_expansion(expansion) - { - assert(m_expansion > 0); - next_interval_impl(); - } - - inline bool is_empty_impl() const - { - return m_current_interval.start == std::numeric_limits::max(); - } - - inline void next_interval_impl() - { - auto& memory_pool = MemoryPool::getInstance(); - - m_current_interval.start = std::numeric_limits::max(); - - // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) - { - const SetTraverser& set_traverser = memory_pool.at(offset); - if (!set_traverser.is_empty() && (set_traverser.current_interval().start - m_expansion < m_current_interval.start)) - { - m_current_interval.start = set_traverser.current_interval().start - m_expansion; - m_current_interval.end = set_traverser.current_interval().end + m_expansion; - } - } - // Now we find the end of the interval, i.e. the largest set_traverser.current_interval().end - // such that set_traverser.current_interval().start - expansion < m_current_interval.end - bool is_done = false; - while (!is_done) - { - is_done = true; - // advance set traverses that are behind current interval - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) - { - SetTraverser& set_traverser = memory_pool.at(offset); - while (!set_traverser.is_empty() && set_traverser.current_interval().end + m_expansion <= m_current_interval.end) - { - set_traverser.next_interval(); - } - } - // try to find a new end - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) - { - const SetTraverser& set_traverser = memory_pool.at(offset); - // there is an overlap - if (!set_traverser.is_empty() && set_traverser.current_interval().start - m_expansion <= m_current_interval.end) - { - is_done = false; - m_current_interval.end = set_traverser.current_interval().end + m_expansion; - } - } - } - } - - inline current_interval_t current_interval_impl() const - { - return m_current_interval; - } - - private: - SetTraverserOffsetRange m_set_traverser_offsets; - value_t m_expansion; - interval_t m_current_interval; - bool m_isEmpty; - }; - + + template + class ExpansionTraverser : public SetTraverserBase> + { + using Self = ExpansionTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + using SetTraverserIterator = typename std::vector::iterator; + using SetTraverserOffsetRange = MemoryPool::OffsetRange; + using SetTraverserOffset = MemoryPool::Distance; + + ExpansionTraverser(const SetTraverserOffset first_set_traverser_offset, + const SetTraverserOffset bound_set_traverser_offset, + const value_t expansion) + : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) + , m_expansion(expansion) + { + assert(m_expansion > 0); + next_interval_impl(); + } + + inline bool is_empty_impl() const + { + return m_current_interval.start == std::numeric_limits::max(); + } + + inline void next_interval_impl() + { + auto& memory_pool = MemoryPool::getInstance(); + + m_current_interval.start = std::numeric_limits::max(); + + // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + { + const SetTraverser& set_traverser = memory_pool.at(offset); + if (!set_traverser.is_empty() && (set_traverser.current_interval().start - m_expansion < m_current_interval.start)) + { + m_current_interval.start = set_traverser.current_interval().start - m_expansion; + m_current_interval.end = set_traverser.current_interval().end + m_expansion; + } + } + // Now we find the end of the interval, i.e. the largest set_traverser.current_interval().end + // such that set_traverser.current_interval().start - expansion < m_current_interval.end + bool is_done = false; + while (!is_done) + { + is_done = true; + // advance set traverses that are behind current interval + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + { + SetTraverser& set_traverser = memory_pool.at(offset); + while (!set_traverser.is_empty() && set_traverser.current_interval().end + m_expansion <= m_current_interval.end) + { + set_traverser.next_interval(); + } + } + // try to find a new end + for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + { + const SetTraverser& set_traverser = memory_pool.at(offset); + // there is an overlap + if (!set_traverser.is_empty() && set_traverser.current_interval().start - m_expansion <= m_current_interval.end) + { + is_done = false; + m_current_interval.end = set_traverser.current_interval().end + m_expansion; + } + } + } + } + + inline current_interval_t current_interval_impl() const + { + return m_current_interval; + } + + private: + + SetTraverserOffsetRange m_set_traverser_offsets; + value_t m_expansion; + interval_t m_current_interval; + bool m_isEmpty; + }; + } // namespace samurai diff --git a/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp b/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp index 5d591daf0..ab47787a7 100644 --- a/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp +++ b/include/samurai/subset/traversers/last_dim_expansion_traverser.hpp @@ -8,8 +8,8 @@ namespace samurai { - template - class LastDimExpansionTraverser; + template + class LastDimExpansionTraverser; template struct SetTraverserTraits> @@ -19,55 +19,58 @@ namespace samurai using interval_t = typename SetTraverserTraits::interval_t; using current_interval_t = const interval_t&; }; - - template - class LastDimExpansionTraverser : public SetTraverserBase< LastDimExpansionTraverser > - { - using Self = LastDimExpansionTraverser; - public: - SAMURAI_SET_TRAVERSER_TYPEDEFS - - LastDimExpansionTraverser(const SetTraverser& set_traverser, const value_t expansion) - : m_set_traverser(set_traverser) - , m_expansion(expansion) - { - assert(m_expansion > 0); - next_interval_impl(); - } - - inline bool is_empty_impl() const - { - return m_isEmpty; - } - - inline void next_interval_impl() - { - m_isEmpty = m_set_traverser.is_empty(); - - if (!m_isEmpty) - { - m_current_interval.start = m_set_traverser.current_interval().start - m_expansion; - m_current_interval.end = m_set_traverser.current_interval().end + m_expansion; - - m_set_traverser.next_interval(); - while (!m_set_traverser.is_empty() and m_set_traverser.current_interval().start - m_expansion <= m_current_interval.end) - { - m_current_interval.end = m_set_traverser.current_interval().end + m_expansion; - m_set_traverser.next_interval(); - } - } - } - - inline current_interval_t current_interval_impl() const - { - return m_current_interval; - } - - private: - SetTraverser m_set_traverser; - value_t m_expansion; - interval_t m_current_interval; - bool m_isEmpty; - }; + + template + class LastDimExpansionTraverser : public SetTraverserBase> + { + using Self = LastDimExpansionTraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + LastDimExpansionTraverser(const SetTraverser& set_traverser, const value_t expansion) + : m_set_traverser(set_traverser) + , m_expansion(expansion) + { + assert(m_expansion > 0); + next_interval_impl(); + } + + inline bool is_empty_impl() const + { + return m_isEmpty; + } + + inline void next_interval_impl() + { + m_isEmpty = m_set_traverser.is_empty(); + + if (!m_isEmpty) + { + m_current_interval.start = m_set_traverser.current_interval().start - m_expansion; + m_current_interval.end = m_set_traverser.current_interval().end + m_expansion; + + m_set_traverser.next_interval(); + while (!m_set_traverser.is_empty() and m_set_traverser.current_interval().start - m_expansion <= m_current_interval.end) + { + m_current_interval.end = m_set_traverser.current_interval().end + m_expansion; + m_set_traverser.next_interval(); + } + } + } + + inline current_interval_t current_interval_impl() const + { + return m_current_interval; + } + + private: + + SetTraverser m_set_traverser; + value_t m_expansion; + interval_t m_current_interval; + bool m_isEmpty; + }; } // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index ceec31304..75353777b 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -32,8 +32,8 @@ namespace samurai { using Self = ProjectionTraverser; - using SetTraverserOffsetRange = MemoryPool::OffsetRange; - using SetTraverserOffset = MemoryPool::Distance; + using SetTraverserOffsetRange = MemoryPool::OffsetRange; + using SetTraverserOffset = MemoryPool::Distance; public: @@ -44,13 +44,13 @@ namespace samurai , m_projectionType(projectionType) , m_shift(shift) , m_isEmpty(MemoryPool::getInstance().at(set_traverser_offset).is_empty()) - { - auto& memory_pool = MemoryPool::getInstance(); - + { + auto& memory_pool = MemoryPool::getInstance(); + if (!m_isEmpty) - { - SetTraverser& set_traverser = memory_pool.at(set_traverser_offset); - + { + SetTraverser& set_traverser = memory_pool.at(set_traverser_offset); + if (m_projectionType == ProjectionType::COARSEN) { m_current_interval.start = coarsen_start(set_traverser.current_interval()); @@ -67,7 +67,7 @@ namespace samurai } } else - { + { m_current_interval.start = set_traverser.current_interval().start << shift; m_current_interval.end = set_traverser.current_interval().end << shift; } @@ -77,16 +77,18 @@ namespace samurai /* * This constructor only works for coarsening */ - ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, const SetTraverserOffset bound_set_traverser_offset, const std::size_t shift) + ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, + const SetTraverserOffset bound_set_traverser_offset, + const std::size_t shift) : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) - { + { next_interval_coarsen(); } inline bool is_empty_impl() const - { + { return m_isEmpty; } @@ -98,8 +100,8 @@ namespace samurai } else { - SetTraverser& set_traverser = MemoryPool::getInstance().at(m_set_traverser_offsets.first); - + SetTraverser& set_traverser = MemoryPool::getInstance().at(m_set_traverser_offsets.first); + set_traverser.next_interval(); m_isEmpty = set_traverser.is_empty(); if (!m_isEmpty) @@ -116,17 +118,17 @@ namespace samurai } private: - + inline void next_interval_coarsen() { - auto& memory_pool = MemoryPool::getInstance(); - + auto& memory_pool = MemoryPool::getInstance(); + m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { - const SetTraverser& set_traverser = memory_pool.at(offset); - + const SetTraverser& set_traverser = memory_pool.at(offset); + if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) < m_current_interval.start)) { m_current_interval.start = coarsen_start(set_traverser.current_interval()); @@ -142,8 +144,8 @@ namespace samurai // advance set traverses that are behind current interval for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { - SetTraverser& set_traverser = memory_pool.at(offset); - + SetTraverser& set_traverser = memory_pool.at(offset); + while (!set_traverser.is_empty() && (coarsen_end(set_traverser.current_interval()) <= m_current_interval.end)) { set_traverser.next_interval(); @@ -152,8 +154,8 @@ namespace samurai // try to find a new end for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) { - const SetTraverser& set_traverser = memory_pool.at(offset); - + const SetTraverser& set_traverser = memory_pool.at(offset); + // there is an overlap if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) <= m_current_interval.end)) { @@ -170,16 +172,16 @@ namespace samurai return interval.start >> m_shift; } - inline value_t coarsen_end(const interval_t& interval) const + inline value_t coarsen_end(const interval_t& interval) const { return ((interval.end - 1) >> m_shift) + 1; } - SetTraverserOffsetRange m_set_traverser_offsets; - ProjectionType m_projectionType; - std::size_t m_shift; - interval_t m_current_interval; - bool m_isEmpty; + SetTraverserOffsetRange m_set_traverser_offsets; + ProjectionType m_projectionType; + std::size_t m_shift; + interval_t m_current_interval; + bool m_isEmpty; }; } // namespace samurai diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 85e1ee734..3171b246c 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -14,8 +14,8 @@ #include #include -#include #include +#include namespace samurai { @@ -515,129 +515,133 @@ namespace samurai } } - TEST(subset, expand) - { - using interval_t = typename LevelCellArray<2>::interval_t; - using expected_t = std::vector>; - - LevelCellArray<2> ca; - - ca.add_interval_back({0, 1}, {0}); - - { - const auto translated_ca = translate(ca, {3 + 1, 0}); - const auto joined_cas = union_(ca, translated_ca); - - const auto set = expand(joined_cas, 3); - - expected_t expected{ - {-3, {-3, 8}}, - {-2, {-3, 8}}, - {-1, {-3, 8}}, - { 0, {-3, 8}}, - { 1, {-3, 8}}, - { 2, {-3, 8}}, - { 3, {-3, 8}} - }; - - bool is_set_empty = true; - std::size_t ie = 0; - set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) - { - is_set_empty = false; - EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); - }); - EXPECT_EQ(ie, expected.size()); - EXPECT_FALSE(is_set_empty); - } - - { - const auto translated_ca = translate(ca, {0, 3+1}); - const auto joined_cas = union_(ca, translated_ca); - - const auto set = expand(joined_cas, 3); - - expected_t expected{ - {-3, {-3, 4}}, - {-2, {-3, 4}}, - {-1, {-3, 4}}, - { 0, {-3, 4}}, - { 1, {-3, 4}}, - { 2, {-3, 4}}, - { 3, {-3, 4}}, - { 4, {-3, 4}}, - { 5, {-3, 4}}, - { 6, {-3, 4}}, - { 7, {-3, 4}} - }; - - bool is_set_empty = true; - std::size_t ie = 0; - set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) - { - is_set_empty = false; - EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); - }); - EXPECT_EQ(ie, expected.size()); - EXPECT_FALSE(is_set_empty); - } - { - const auto translated_ca = translate(ca, {3+1, 3+1}); - const auto joined_cas = union_(ca, translated_ca); - - const auto set = expand(joined_cas, 3); - - expected_t expected{ - {-3, {-3, 4}}, - {-2, {-3, 4}}, - {-1, {-3, 4}}, - { 0, {-3, 4}}, - { 1, {-3, 8}}, - { 2, {-3, 8}}, - { 3, {-3, 8}}, - { 4, { 1, 8}}, - { 5, { 1, 8}}, - { 6, { 1, 8}}, - { 7, { 1, 8}} - }; - - bool is_set_empty = true; - std::size_t ie = 0; - set([&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) - { - is_set_empty = false; - EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); - }); - EXPECT_EQ(ie, expected.size()); - EXPECT_FALSE(is_set_empty); - - const auto lca_joined_cas = joined_cas.to_lca(); - const auto lca_set = set.to_lca(); - } - } - - TEST(subset, contract) - { - LevelCellArray<2> ca; - - ca.add_interval_back({0, 1}, {0}); - - { - const auto translated_ca = translate(ca, {3 + 1, 0}); - const auto joined_cas = union_(ca, translated_ca); - - const auto set = contract(joined_cas, 1); - - bool is_set_empty = true; - set([&is_set_empty](const auto& x_interval, const auto& yz) - { - fmt::print("x_interval = {} -- yz = {}", x_interval, yz[0]); - is_set_empty = false; - }); - EXPECT_TRUE(is_set_empty); - //~ EXPECT_TRUE(set.empty()); - } - } + TEST(subset, expand) + { + using interval_t = typename LevelCellArray<2>::interval_t; + using expected_t = std::vector>; + + LevelCellArray<2> ca; + + ca.add_interval_back({0, 1}, {0}); + + { + const auto translated_ca = translate(ca, {3 + 1, 0}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = expand(joined_cas, 3); + + expected_t expected{ + {-3, {-3, 8}}, + {-2, {-3, 8}}, + {-1, {-3, 8}}, + {0, {-3, 8}}, + {1, {-3, 8}}, + {2, {-3, 8}}, + {3, {-3, 8}} + }; + + bool is_set_empty = true; + std::size_t ie = 0; + set( + [&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) + { + is_set_empty = false; + EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); + }); + EXPECT_EQ(ie, expected.size()); + EXPECT_FALSE(is_set_empty); + } + + { + const auto translated_ca = translate(ca, {0, 3 + 1}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = expand(joined_cas, 3); + + expected_t expected{ + {-3, {-3, 4}}, + {-2, {-3, 4}}, + {-1, {-3, 4}}, + {0, {-3, 4}}, + {1, {-3, 4}}, + {2, {-3, 4}}, + {3, {-3, 4}}, + {4, {-3, 4}}, + {5, {-3, 4}}, + {6, {-3, 4}}, + {7, {-3, 4}} + }; + + bool is_set_empty = true; + std::size_t ie = 0; + set( + [&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) + { + is_set_empty = false; + EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); + }); + EXPECT_EQ(ie, expected.size()); + EXPECT_FALSE(is_set_empty); + } + { + const auto translated_ca = translate(ca, {3 + 1, 3 + 1}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = expand(joined_cas, 3); + + expected_t expected{ + {-3, {-3, 4}}, + {-2, {-3, 4}}, + {-1, {-3, 4}}, + {0, {-3, 4}}, + {1, {-3, 8}}, + {2, {-3, 8}}, + {3, {-3, 8}}, + {4, {1, 8} }, + {5, {1, 8} }, + {6, {1, 8} }, + {7, {1, 8} } + }; + + bool is_set_empty = true; + std::size_t ie = 0; + set( + [&expected, &is_set_empty, &ie](const auto& x_interval, const auto& yz) + { + is_set_empty = false; + EXPECT_EQ(expected[ie++], std::make_pair(yz[0], x_interval)); + }); + EXPECT_EQ(ie, expected.size()); + EXPECT_FALSE(is_set_empty); + + const auto lca_joined_cas = joined_cas.to_lca(); + const auto lca_set = set.to_lca(); + } + } + + TEST(subset, contract) + { + LevelCellArray<2> ca; + + ca.add_interval_back({0, 1}, {0}); + + { + const auto translated_ca = translate(ca, {3 + 1, 0}); + const auto joined_cas = union_(ca, translated_ca); + + const auto set = contract(joined_cas, 1); + + bool is_set_empty = true; + set( + [&is_set_empty](const auto& x_interval, const auto& yz) + { + fmt::print("x_interval = {} -- yz = {}", x_interval, yz[0]); + is_set_empty = false; + }); + EXPECT_TRUE(is_set_empty); + //~ EXPECT_TRUE(set.empty()); + } + } TEST(subset, translate) { From 1f6794b94a2742d22969c747b4fcabf088d8be4f Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 17:06:49 +0200 Subject: [PATCH 09/28] minor update --- include/samurai/algorithm/update.hpp | 10 ---------- include/samurai/boundary.hpp | 2 +- include/samurai/subset/contraction.hpp | 4 ++-- include/samurai/subset/expansion.hpp | 4 ++-- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/include/samurai/algorithm/update.hpp b/include/samurai/algorithm/update.hpp index 0a3fba92a..196e8fed5 100644 --- a/include/samurai/algorithm/update.hpp +++ b/include/samurai/algorithm/update.hpp @@ -18,8 +18,6 @@ #include "graduation.hpp" #include "utils.hpp" -#include "fmt/ranges.h" - #ifndef NDEBUG #include "../io/hdf5.hpp" #endif @@ -136,14 +134,6 @@ namespace samurai auto bc_ghosts_in_other_directions = domain_boundary_outer_layer(mesh, proj_level, n_bc_ghosts); auto projection_ghosts_no_bc_ghosts = difference(projection_ghosts, bc_ghosts_in_other_directions); - const auto lca_projection_ghosts = projection_ghosts.to_lca(bc_ghosts_in_other_directions.origin_point(), - bc_ghosts_in_other_directions.scaling_factor()); - const auto lca_projection_ghosts_no_bc_ghosts = projection_ghosts_no_bc_ghosts.to_lca( - bc_ghosts_in_other_directions.origin_point(), - bc_ghosts_in_other_directions.scaling_factor()); - const auto lca_domain = domain.to_lca(bc_ghosts_in_other_directions.origin_point(), - bc_ghosts_in_other_directions.scaling_factor()); - project_bc(projection_ghosts_no_bc_ghosts, proj_level, direction, layer, field); } } diff --git a/include/samurai/boundary.hpp b/include/samurai/boundary.hpp index ac505f65e..d5ade2d32 100644 --- a/include/samurai/boundary.hpp +++ b/include/samurai/boundary.hpp @@ -9,7 +9,7 @@ namespace samurai { using mesh_id_t = typename Mesh::mesh_id_t; - auto& cells = mesh[mesh_id_t::cells][level]; + const auto& cells = mesh[mesh_id_t::cells][level]; return difference(cells, translate(self(domain).on(level), -layer_width * direction)); } diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 83ae68b3c..4d28c15f3 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -98,14 +98,14 @@ namespace samurai } template - auto contract(const Set& set, const typename Contraction>::value_t contraction) + auto contract(const Set& set, const typename Contraction>::value_t& contraction) { return Contraction(self(set), contraction); } template auto contract(const Set& set, - const typename Contraction>::value_t contraction, + const typename Contraction>::value_t& contraction, const typename Contraction>::do_contraction_t& do_contraction) // idk how to make this // more readable, // perhaps a traits... diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 7631b1d7b..971b55a4f 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -194,14 +194,14 @@ namespace samurai } template - auto expand(const Set& set, const typename Contraction>::value_t expansion) + auto expand(const Set& set, const typename Contraction>::value_t& expansion) { return Expansion(self(set), expansion); } template auto expand(const Set& set, - const typename Contraction>::value_t expansion, + const typename Contraction>::value_t& expansion, const typename Contraction>::do_expansion_t& do_expansion) { return Expansion(self(set), expansion, do_expansion); From de91bbd827b97967431b7754cd5f746c2003e4f2 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 17:13:49 +0200 Subject: [PATCH 10/28] minor update --- include/samurai/boundary.hpp | 2 +- include/samurai/level_cell_array.hpp | 2 +- include/samurai/subset/fixed_capacity_array.hpp | 2 +- include/samurai/subset/lca_view.hpp | 2 +- include/samurai/subset/traversers/expansion_traverser.hpp | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/samurai/boundary.hpp b/include/samurai/boundary.hpp index d5ade2d32..b22d62ae2 100644 --- a/include/samurai/boundary.hpp +++ b/include/samurai/boundary.hpp @@ -43,7 +43,7 @@ namespace samurai { using mesh_id_t = typename Mesh::mesh_id_t; - auto& cells = mesh[mesh_id_t::cells][level]; + const auto& cells = mesh[mesh_id_t::cells][level]; return difference(cells, contract(self(mesh.domain()).on(level), 1)); } diff --git a/include/samurai/level_cell_array.hpp b/include/samurai/level_cell_array.hpp index 2bccd81eb..2c9db2316 100644 --- a/include/samurai/level_cell_array.hpp +++ b/include/samurai/level_cell_array.hpp @@ -98,7 +98,7 @@ namespace samurai //~ LevelCellArray(Subset set); template - LevelCellArray(const SetBase& set); + explicit LevelCellArray(const SetBase& set); template LevelCellArray(const SetBase& set, const coords_t& origin_point, const double scaling_factor); diff --git a/include/samurai/subset/fixed_capacity_array.hpp b/include/samurai/subset/fixed_capacity_array.hpp index 48ee6bed4..f8798d1d1 100644 --- a/include/samurai/subset/fixed_capacity_array.hpp +++ b/include/samurai/subset/fixed_capacity_array.hpp @@ -18,7 +18,7 @@ class FixedCapacityArray { } - FixedCapacityArray(const std::size_t size, const T& value = T()) + explicit FixedCapacityArray(const std::size_t size, const T& value = T()) requires(std::is_trivially_constructible::value) { assert(size <= N); diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index f7904db75..0d96a88f3 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -35,7 +35,7 @@ namespace samurai using const_interval_iterator = typename std::vector::const_iterator; - LCAView(const LCA& lca) + explicit LCAView(const LCA& lca) : m_lca(lca) { } diff --git a/include/samurai/subset/traversers/expansion_traverser.hpp b/include/samurai/subset/traversers/expansion_traverser.hpp index 14edcbf6e..524a71a49 100644 --- a/include/samurai/subset/traversers/expansion_traverser.hpp +++ b/include/samurai/subset/traversers/expansion_traverser.hpp @@ -103,7 +103,6 @@ namespace samurai SetTraverserOffsetRange m_set_traverser_offsets; value_t m_expansion; interval_t m_current_interval; - bool m_isEmpty; }; } // namespace samurai From dfa353d257149806b47e571ca9b0b9877ff7eba5 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 17:21:43 +0200 Subject: [PATCH 11/28] minor update --- include/samurai/level_cell_array.hpp | 3 --- include/samurai/mesh.hpp | 10 ++++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/samurai/level_cell_array.hpp b/include/samurai/level_cell_array.hpp index 2c9db2316..18b8c1eba 100644 --- a/include/samurai/level_cell_array.hpp +++ b/include/samurai/level_cell_array.hpp @@ -94,9 +94,6 @@ namespace samurai LevelCellArray() = default; LevelCellArray(const LevelCellList& lcl); - //~ template - //~ LevelCellArray(Subset set); - template explicit LevelCellArray(const SetBase& set); diff --git a/include/samurai/mesh.hpp b/include/samurai/mesh.hpp index 1fa2192f7..ed17be689 100644 --- a/include/samurai/mesh.hpp +++ b/include/samurai/mesh.hpp @@ -815,16 +815,18 @@ namespace samurai { if constexpr (dim == 2) { - m_corners.push_back(difference( - m_domain, - union_(translate(m_domain, direction_t{-direction[0], 0}), translate(m_domain, direction_t{0, -direction[1]})))); + m_corners.push_back(difference(m_domain, + union_(translate(m_domain, direction_t{-direction[0], 0}), + translate(m_domain, direction_t{0, -direction[1]}))) + .to_lca()); } else if constexpr (dim == 3) { m_corners.push_back(difference(m_domain, union_(translate(m_domain, direction_t{-direction[0], 0, 0}), translate(m_domain, direction_t{0, -direction[1], 0}), - translate(m_domain, direction_t{0, 0, -direction[2]})))); + translate(m_domain, direction_t{0, 0, -direction[2]}))) + .to_lca()); } }); } From dbe1c8c05f7dd3463915555dfee8c2d23dc0dcec Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 17:34:22 +0200 Subject: [PATCH 12/28] minor update --- include/samurai/subset/box_view.hpp | 3 ++- include/samurai/subset/contraction.hpp | 6 +++--- include/samurai/subset/expansion.hpp | 12 ++++++------ include/samurai/subset/lca_view.hpp | 10 +++++----- include/samurai/subset/nary_set_operator.hpp | 2 +- include/samurai/subset/projection.hpp | 9 +++++---- include/samurai/subset/translation.hpp | 4 ++-- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 924392dc7..c55ebe450 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -31,7 +31,8 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + + //~ SAMURAI_SET_CONSTEXPRS BoxView(const std::size_t level, const B& box) : m_level(level) diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 4d28c15f3..2e6302680 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -31,10 +31,10 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + //~ SAMURAI_SET_CONSTEXPRS - using contraction_t = std::array; - using do_contraction_t = std::array; + using contraction_t = std::array; + using do_contraction_t = std::array; Contraction(const Set& set, const contraction_t& contraction) : m_set(set) diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 971b55a4f..9319df3c4 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -56,10 +56,10 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + //~ SAMURAI_SET_CONSTEXPRS - using expansion_t = std::array; - using do_expansion_t = std::array; + using expansion_t = std::array; + using do_expansion_t = std::array; Expansion(const Set& set, const expansion_t& expansions) : m_set(set) @@ -98,7 +98,7 @@ namespace samurai ~Expansion() { - static_for<0, dim - 1>::apply( + static_for<0, Base::dim - 1>::apply( [this](const auto d) { using Work = MemoryPool>; @@ -130,7 +130,7 @@ namespace samurai template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { - if constexpr (d == dim - 1) + if constexpr (d == Base::dim - 1) { return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); } @@ -146,7 +146,7 @@ namespace samurai const auto set_traversers_offsets = work.requestChunk(WorkSize(2 * (m_expansions[d + 1] + 1))); auto end_offset = set_traversers_offsets.first; - xt::xtensor_fixed> tmp_index(index); + xt::xtensor_fixed> tmp_index(index); for (value_t width = 0; width != m_expansions[d + 1] + 1; ++width) { diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 0d96a88f3..b70ccb097 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -31,7 +31,7 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + //~ SAMURAI_SET_CONSTEXPRS using const_interval_iterator = typename std::vector::const_iterator; @@ -59,10 +59,10 @@ namespace samurai inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { return get_traverser_impl_detail(index, - m_lca[dim - 1].cbegin(), - m_lca[dim - 1].cend(), + m_lca[Base::dim - 1].cbegin(), + m_lca[Base::dim - 1].cend(), d_ic, - std::integral_constant{}); + std::integral_constant{}); } template @@ -72,7 +72,7 @@ namespace samurai std::integral_constant d_ic, std::integral_constant dCur_ic) const { - if constexpr (dCur != dim - 1) + if constexpr (dCur != Base::dim - 1) { const auto& y = index[dCur]; const auto& y_offsets = m_lca.offsets(dCur + 1); diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index c14681baa..c262e8083 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -65,7 +65,7 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + //~ SAMURAI_SET_CONSTEXPRS using Childrens = std::tuple; diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 3bf3ce711..546681f62 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -53,7 +53,8 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + + //~ SAMURAI_SET_CONSTEXPRS Projection(const Set& set, const std::size_t level) : m_set(set) @@ -91,7 +92,7 @@ namespace samurai ~Projection() { - static_for<0, dim>::apply( + static_for<0, Base::dim>::apply( [this](const auto d) { using Work = MemoryPool>; @@ -131,7 +132,7 @@ namespace samurai if (m_projectionType == ProjectionType::COARSEN) { - if constexpr (d != dim - 1) + if constexpr (d != Base::dim - 1) { const auto set_traversers_offsets = work.requestChunk(1 << m_shift); auto end_offset = set_traversers_offsets.first; @@ -139,7 +140,7 @@ namespace samurai const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; - xt::xtensor_fixed> index(_index << m_shift); + xt::xtensor_fixed> index(_index << m_shift); for (index[d] = ymin; index[d] != ymax; ++index[d]) { diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 8b2b3387b..d48b4c172 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -34,9 +34,9 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - SAMURAI_SET_CONSTEXPRS + //~ SAMURAI_SET_CONSTEXPRS - using translation_t = xt::xtensor_fixed>; + using translation_t = xt::xtensor_fixed>; template Translation(const Set& set, const translation_expr_t& translation_expr) From 2eb0c7043055bbeae75996217e188d681f414374 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 1 Oct 2025 17:42:51 +0200 Subject: [PATCH 13/28] minor update --- include/samurai/subset/box_view.hpp | 5 ++++- include/samurai/subset/contraction.hpp | 5 ++++- include/samurai/subset/expansion.hpp | 5 ++++- include/samurai/subset/lca_view.hpp | 5 ++++- include/samurai/subset/memory_pool.hpp | 1 - include/samurai/subset/nary_set_operator.hpp | 15 ++++++++++++--- include/samurai/subset/projection.hpp | 5 ++++- include/samurai/subset/set_base.hpp | 4 ++-- include/samurai/subset/translation.hpp | 5 ++++- 9 files changed, 38 insertions(+), 12 deletions(-) diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index c55ebe450..6193451c2 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -20,7 +20,10 @@ namespace samurai template using traverser_t = BoxTraverser; - static constexpr std::size_t dim = B::dim; + static constexpr std::size_t dim() + { + return B::dim; + } }; template diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 2e6302680..6f703f7ed 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -20,7 +20,10 @@ namespace samurai template using traverser_t = ContractionTraverser>; - static constexpr std::size_t dim = Set::dim; + static constexpr std::size_t dim() + { + return Set::dim; + } }; template diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 9319df3c4..b54f46e2d 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -23,7 +23,10 @@ namespace samurai LastDimExpansionTraverser>, ExpansionTraverser>>; - static constexpr std::size_t dim = Set::dim; + static constexpr std::size_t dim() + { + return Set::dim; + } }; namespace detail diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index b70ccb097..106727f8a 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -20,7 +20,10 @@ namespace samurai template using traverser_t = LCATraverser; - static constexpr std::size_t dim = LCA::dim; + static constexpr std::size_t dim() + { + return LCA::dim; + } }; template diff --git a/include/samurai/subset/memory_pool.hpp b/include/samurai/subset/memory_pool.hpp index 3e86f84f5..00b922638 100644 --- a/include/samurai/subset/memory_pool.hpp +++ b/include/samurai/subset/memory_pool.hpp @@ -25,7 +25,6 @@ class MemoryPool using const_Reference = const Element&; using Distance = typename AllocatorTraits::difference_type; using Size = typename AllocatorTraits::size_type; - //~ using OffsetRange = std::ranges::iota_view; static_assert(std::is_move_constructible::value or std::is_trivially_copyable::value); diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index c262e8083..915c4d6c9 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -30,7 +30,10 @@ namespace samurai template using traverser_t = UnionTraverser...>; - static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; + static constexpr std::size_t dim() + { + return std::tuple_element_t<0, std::tuple>::dim; + } }; template @@ -41,7 +44,10 @@ namespace samurai template using traverser_t = IntersectionTraverser...>; - static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; + static constexpr std::size_t dim() + { + return std::tuple_element_t<0, std::tuple>::dim; + } }; template @@ -54,7 +60,10 @@ namespace samurai DifferenceTraverser...>, DifferenceIdTraverser...>>; - static constexpr std::size_t dim = std::tuple_element_t<0, std::tuple>::dim; + static constexpr std::size_t dim() + { + return std::tuple_element_t<0, std::tuple>::dim; + } }; template diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 546681f62..2966532d8 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -23,7 +23,10 @@ namespace samurai template using traverser_t = ProjectionTraverser>; - static constexpr std::size_t dim = Set::dim; + static constexpr std::size_t dim() + { + return Set::dim; + } }; namespace detail diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index e390726d8..9026f92fe 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -43,10 +43,10 @@ namespace samurai using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; - using to_lca_t = LevelCellArray; + using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; - static constexpr std::size_t dim = DerivedTraits::dim; + static constexpr std::size_t dim = DerivedTraits::dim(); const Derived& derived_cast() const { diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index d48b4c172..3a0ef5dbf 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -23,7 +23,10 @@ namespace samurai template using traverser_t = TranslationTraverser>; - static constexpr std::size_t dim = Set::dim; + static constexpr std::size_t dim() + { + return Set::dim; + } }; template From 2c4f65d635d3e42814c581491d5b02a2215b6019 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Fri, 3 Oct 2025 14:34:10 +0200 Subject: [PATCH 14/28] a --- include/samurai/subset/apply.hpp | 4 + include/samurai/subset/box_view.hpp | 12 +- include/samurai/subset/contraction.hpp | 13 +- include/samurai/subset/expansion.hpp | 94 +++--- .../samurai/subset/fixed_capacity_array.hpp | 197 ------------- include/samurai/subset/lca_view.hpp | 15 +- include/samurai/subset/memory_pool.hpp | 272 ------------------ include/samurai/subset/nary_set_operator.hpp | 21 +- include/samurai/subset/projection.hpp | 97 +++---- include/samurai/subset/set_base.hpp | 19 +- include/samurai/subset/translation.hpp | 13 +- .../subset/traversers/expansion_traverser.hpp | 26 +- .../traversers/projection_traverser.hpp | 66 ++--- include/samurai/subset/work.hpp | 2 - 14 files changed, 210 insertions(+), 641 deletions(-) delete mode 100644 include/samurai/subset/fixed_capacity_array.hpp delete mode 100644 include/samurai/subset/memory_pool.hpp delete mode 100644 include/samurai/subset/work.hpp diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index eccb563be..c75ebfb62 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -15,6 +15,8 @@ namespace samurai using traverser_t = typename Set::template traverser_t; using current_interval_t = typename traverser_t::current_interval_t; + set.init_get_traverser_work(1, d_ic); + for (traverser_t traverser = set.get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) { current_interval_t interval = traverser.current_interval(); @@ -31,6 +33,8 @@ namespace samurai } } } + + set.clear_get_traverser_work(d_ic); } } diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 6193451c2..b2b6153b3 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -35,8 +35,6 @@ namespace samurai SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS - BoxView(const std::size_t level, const B& box) : m_level(level) , m_box(box) @@ -66,6 +64,16 @@ namespace samurai : traverser_t(0, 0); } + template + constexpr inline void init_get_traverser_work_impl(const std::size_t, std::integral_constant) const + { + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant) const + { + } + private: std::size_t m_level; diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 6f703f7ed..784e66144 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -34,7 +34,6 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS using contraction_t = std::array; using do_contraction_t = std::array; @@ -82,6 +81,18 @@ namespace samurai return Base::empty_default_impl(); } + template + inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + { + m_set.init_get_traverser_work(n_traversers, d_ic); + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + { + m_set.clear_get_traverser_work(d_ic); + } + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index b54f46e2d..d873036b4 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -41,9 +41,9 @@ namespace samurai using child_traverser_t = typename Set::template traverser_t; template - using array_of_child_traverser_offset_range_t = std::vector>::OffsetRange>; + using array_of_child_traverser_t = std::vector>; - using Type = std::tuple...>; + using Type = std::tuple...>; static_assert(std::tuple_size::value == Set::dim - 1); }; @@ -53,13 +53,12 @@ namespace samurai template class Expansion : public SetBase> { - using Self = Expansion; - using OffsetRangeWork = detail::ExpansionWork>::Type; + using Self = Expansion; + using ChildTraverserArray = detail::ExpansionWork>::Type; public: SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS using expansion_t = std::array; using do_expansion_t = std::array; @@ -99,22 +98,6 @@ namespace samurai { } - ~Expansion() - { - static_for<0, Base::dim - 1>::apply( - [this](const auto d) - { - using Work = MemoryPool>; - - auto& work = Work::getInstance(); - - for (auto& offset_range : std::get(m_work_offsetRanges)) - { - work.freeChunk(offset_range); - } - }); - } - inline std::size_t level_impl() const { return m_set.level(); @@ -130,55 +113,70 @@ namespace samurai return m_set.empty(); } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + template + inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const { if constexpr (d == Base::dim - 1) { - return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); + m_set.init_get_traverser_work_impl(n_traversers, d_ic); } else { - using Work = MemoryPool>; - using WorkSize = typename Work::Size; + const std::size_t my_work_size = n_traversers * 2 * std::size_t(m_expansions[d + 1] + 1); - Work& work = Work::getInstance(); + auto& childTraversers = std::get(m_work_childTraversers); + childTraversers.clear(); + childTraversers.reserve(my_work_size); + + m_set.init_get_traverser_work_impl(my_work_size, d_ic); + } + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + { + if constexpr (d != Base::dim - 1) + { + auto& childTraversers = std::get(m_work_childTraversers); - auto& offsetRange = std::get(m_work_offsetRanges); + childTraversers.clear(); + } + m_set.clear_get_traverser_work(d_ic); + } - const auto set_traversers_offsets = work.requestChunk(WorkSize(2 * (m_expansions[d + 1] + 1))); - auto end_offset = set_traversers_offsets.first; + template + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + { + if constexpr (d == Base::dim - 1) + { + return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); + } + else + { + auto& childTraversers = std::get(m_work_childTraversers); xt::xtensor_fixed> tmp_index(index); + const auto childTraversers_begin = childTraversers.end(); + for (value_t width = 0; width != m_expansions[d + 1] + 1; ++width) { tmp_index[d + 1] = index[d + 1] + width; - std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); - if (work.at(end_offset).is_empty()) + childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic)); + if (childTraversers.back().is_empty()) { - std::destroy_at(work.getPtr(end_offset)); - } - else - { - ++end_offset; + childTraversers.pop_back(); } tmp_index[d + 1] = index[d + 1] - width; - std::construct_at(work.getPtr(end_offset), m_set.get_traverser(tmp_index, d_ic)); - if (work.at(end_offset).is_empty()) - { - std::destroy_at(work.getPtr(end_offset)); - } - else + childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic)); + if (childTraversers.back().is_empty()) { - ++end_offset; + childTraversers.pop_back(); } } - offsetRange.push_back(set_traversers_offsets); - - return traverser_t(set_traversers_offsets.first, end_offset, m_expansions[d]); + return traverser_t(childTraversers_begin, childTraversers.end(), m_expansions[d]); } } @@ -187,7 +185,7 @@ namespace samurai Set m_set; expansion_t m_expansions; - mutable OffsetRangeWork m_work_offsetRanges; + mutable ChildTraverserArray m_work_childTraversers; }; template diff --git a/include/samurai/subset/fixed_capacity_array.hpp b/include/samurai/subset/fixed_capacity_array.hpp deleted file mode 100644 index f8798d1d1..000000000 --- a/include/samurai/subset/fixed_capacity_array.hpp +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include - -template -class FixedCapacityArray -{ - using CoreElement = std::conditional_t::value, T, std::aligned_storage_t>; - - public: - - FixedCapacityArray() noexcept - : m_end(begin()) - { - } - - explicit FixedCapacityArray(const std::size_t size, const T& value = T()) - requires(std::is_trivially_constructible::value) - { - assert(size <= N); - m_end = begin() + size; - for (T* it = begin(); it != end(); ++it) - { - std::construct_at(it, value); - } - } - - FixedCapacityArray(const FixedCapacityArray& other) - { - copyFrom(std::cbegin(other), std::cend(other)); - } - - FixedCapacityArray(FixedCapacityArray&& other) noexcept - { - moveFrom(std::cbegin(other), std::cend(other)); - other.clear(); - } - - ~FixedCapacityArray() - { - clear(); - } - - FixedCapacityArray& operator=(const FixedCapacityArray& other) - { - if (this != std::addressof(other)) - { - clear(); - copyFrom(std::cbegin(other), std::cend(other), begin()); - } - return *this; - } - - FixedCapacityArray& operator=(FixedCapacityArray&& other) noexcept - { - if (this != std::addressof(other)) - { - clear(); - moveFrom(std::cbegin(other), std::cend(other), begin()); - other.clear(); - } - return *this; - } - - T* begin() noexcept - { - if constexpr (std::is_trivially_constructible::value) - { - return m_core.data(); - } - else - { - return reinterpret_cast(m_core.data()); - } - } - - T* end() - { - return m_end; - } - - const T* begin() const noexcept - { - if constexpr (std::is_trivially_constructible::value) - { - return m_core.data(); - } - else - { - return reinterpret_cast(m_core.data()); - } - } - - const T* end() const - { - return m_end; - } - - const T& operator[](const std::size_t i) const - { - return *(begin() + i); - } - - T& operator[](const std::size_t i) - { - return *(begin() + i); - } - - std::ptrdiff_t ssize() const - { - return std::distance(begin(), end()); - } - - std::size_t size() const - { - return std::size_t(ssize()); - } - - constexpr std::size_t capacity() const - { - return N; - } - - template - void emplace_back(Args&&... args) - { - assert(size() < N); - std::construct_at(m_end, std::forward(args)...); - ++m_end; - } - - void push_back(const T& value) - { - emplace_back(value); - } - - void pop_back() - { - if (begin() != m_end) - { - --m_end; - std::destroy_at(m_end); - } - } - - void clear() - { - if constexpr (not std::is_trivially_destructible_v) - { - std::destroy(begin(), end()); - } - m_end = begin(); - } - - private: - - void copyFrom(const T* srcBegin, const T* srcEnd) - { - if constexpr (std::is_trivially_copyable::value) - { - std::copy(srcBegin, srcEnd, begin()); - m_end = begin() + std::distance(srcBegin, srcEnd); - } - else - { - m_end = begin(); - for (const T* srcIt = srcBegin; srcIt != srcEnd; ++srcIt, ++m_end) - { - std::construct_at(m_end, *srcIt); - } - } - } - - void moveFrom(const T* srcBegin, const T* srcEnd) - { - if constexpr (std::is_trivially_move_constructible::value) - { - std::move(srcBegin, srcEnd, begin()); - m_end = begin() + std::distance(srcBegin, srcEnd); - } - else - { - m_end = begin(); - for (const T* srcIt = srcBegin; srcIt != srcEnd; ++srcIt, ++m_end) - { - std::construct_at(m_end, std::move(*srcIt)); - } - } - } - - std::array m_core; - T* m_end; -}; diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 106727f8a..cf82b3de5 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -34,7 +34,6 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS using const_interval_iterator = typename std::vector::const_iterator; @@ -58,6 +57,16 @@ namespace samurai return m_lca.empty(); } + template + inline void init_get_traverser_work_impl(const std::size_t, std::integral_constant) const + { + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant) const + { + } + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { @@ -68,6 +77,8 @@ namespace samurai std::integral_constant{}); } + private: + template inline traverser_t get_traverser_impl_detail(const index_t& index, const_interval_iterator begin_y_interval, @@ -123,8 +134,6 @@ namespace samurai } } - private: - const LCA& m_lca; }; diff --git a/include/samurai/subset/memory_pool.hpp b/include/samurai/subset/memory_pool.hpp deleted file mode 100644 index 00b922638..000000000 --- a/include/samurai/subset/memory_pool.hpp +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include -#include -#include -#include - -#include - -template > -class MemoryPool -{ - public: - - using Allocator = typename std::allocator_traits::template rebind_alloc; - using AllocatorTraits = std::allocator_traits; - using Element = typename AllocatorTraits::value_type; - using Pointer = typename AllocatorTraits::pointer; - using const_Pointer = typename AllocatorTraits::const_pointer; - using Reference = Element&; - using const_Reference = const Element&; - using Distance = typename AllocatorTraits::difference_type; - using Size = typename AllocatorTraits::size_type; - - static_assert(std::is_move_constructible::value or std::is_trivially_copyable::value); - - struct OffsetRange - { - Distance first; - Distance bound; - - inline Size size() const - { - return Size(bound - first); - } - }; - - struct Chunk - { - Distance offset; - Size size; - bool isFree; - - friend bool operator<(const Chunk& lhs, const Chunk& rhs) - { - return lhs.offset < rhs.offset; - } - }; - - using ChunkIterator = typename std::vector::iterator; - - MemoryPool(const MemoryPool&) = delete; - MemoryPool& operator=(const MemoryPool&) = delete; - - ~MemoryPool(); - - OffsetRange requestChunk(const Size chunkSize); - - void freeChunk(const OffsetRange offsets); - - Pointer getPtr(const Distance offset) - { - assert(Size(offset) < m_totalSize); - return m_memory + offset; - } - - const_Pointer getPtr(const Distance offset) const - { - assert(Size(offset) < m_totalSize); - return m_memory + offset; - } - - Reference at(const Distance offset) - { - return *getPtr(offset); - } - - const_Reference at(const Distance offset) const - { - return *getPtr(offset); - } - - Reference operator[](const Distance offset) - { - return at(offset); - } - - const_Reference operator[](const Distance offset) const - { - return at(offset); - } - - Size totalSize() const - { - return m_totalSize; - } - - static MemoryPool& getInstance(); - - private: - - MemoryPool() - { - } - - Pointer m_memory = nullptr; - Size m_totalSize = 0; - Allocator m_allocator; - std::vector m_chunks; -}; - -template -MemoryPool& MemoryPool::getInstance() -{ - static MemoryPool instance; - - return instance; -} - -template -MemoryPool::~MemoryPool() -{ - assert(std::all_of(std::begin(m_chunks), - std::end(m_chunks), - [](const Chunk& chunk) -> bool - { - return chunk.isFree; - })); - - m_allocator.deallocate(m_memory, m_totalSize); - - m_memory = nullptr; - m_totalSize = 0; -} - -template -auto MemoryPool::requestChunk(const Size chunkSize) -> OffsetRange -{ - const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), - std::end(m_chunks), - [chunkSize](const Chunk& chunk) -> bool - { - return chunk.isFree and chunk.size >= chunkSize; - }); - - if (chunkIt != std::end(m_chunks)) - { - chunkIt->isFree = false; - const OffsetRange ret(chunkIt->offset, chunkIt->offset + Distance(chunkSize)); - - if (chunkIt->size > chunkSize) - { - // slipt the chunk - const Distance newChunkOffset = chunkIt->offset + Distance(chunkSize); - const Size newChunkSize = chunkIt->size - chunkSize; - - chunkIt->size = chunkSize; - m_chunks.push_back({.offset = newChunkOffset, .size = newChunkSize, .isFree = true}); - } - - return ret; - } - else if (m_memory != nullptr) - { - const Size newTotalSize = std::max(m_totalSize + chunkSize, 2 * m_totalSize); - // we need to reallocate a larger buffer - Pointer newMemory = m_allocator.allocate(newTotalSize); - // we need to move all the data from our buffer to the new one - auto usedChunks = m_chunks - | std::views::filter( - [](const Chunk& chunk) - { - return not chunk.isFree; - }); - - for (const Chunk& chunk : usedChunks) - { - Pointer beginChunk = m_memory + chunk.offset; - Pointer endChunk = beginChunk + chunk.size; - Pointer dstIt = newMemory + chunk.offset; - if constexpr (std::is_trivially_copyable::value) - { - std::copy(beginChunk, endChunk, dstIt); - std::destroy(beginChunk, endChunk); - } - else - { - for (Pointer srcIt = beginChunk; srcIt != endChunk; ++srcIt, ++dstIt) - { - std::construct_at(dstIt, std::move(*srcIt)); - std::destroy_at(srcIt); - } - } - } - // now we can swap the pointers and free newMemory - std::swap(m_memory, newMemory); - m_allocator.deallocate(newMemory, m_totalSize); - - // now we create a new chunk with the correct size - - m_chunks.push_back({.offset = Distance(m_totalSize), .size = chunkSize, .isFree = false}); - OffsetRange ret(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); - - if (newTotalSize != (m_totalSize + chunkSize)) - { - m_chunks.push_back( - {.offset = Distance(m_totalSize + chunkSize), .size = Size(newTotalSize - m_totalSize - chunkSize), .isFree = true}); - } - m_totalSize = newTotalSize; - - return ret; - } - else - { - m_memory = m_allocator.allocate(chunkSize); - m_totalSize = chunkSize; - - m_chunks.push_back({.offset = 0, .size = chunkSize, .isFree = false}); - - return OffsetRange(m_chunks.back().offset, m_chunks.back().offset + Distance(m_chunks.back().size)); - } -} - -template -auto MemoryPool::freeChunk(const OffsetRange offsets) -> void -{ - const ChunkIterator chunkIt = std::find_if(std::begin(m_chunks), - std::end(m_chunks), - [&offsets](const Chunk& chunk) -> bool - { - return (not chunk.isFree) and chunk.offset == offsets.first - and chunk.size == offsets.size(); - }); - - assert(chunkIt != std::end(m_chunks)); - - if (chunkIt != std::end(m_chunks)) - { - chunkIt->isFree = true; - - std::destroy(m_memory + chunkIt->offset, m_memory + chunkIt->offset + chunkIt->size); - - // Coalescing - std::sort(std::begin(m_chunks), std::end(m_chunks)); - - for (ChunkIterator it = std::begin(m_chunks); it != std::end(m_chunks); ++it) - { - if (it->isFree) - { - for (auto nextIt = std::next(it); - nextIt != std::end(m_chunks) and nextIt->isFree and it->offset + Distance(it->size) == nextIt->offset; - ++nextIt) - { - it->size += nextIt->size; - nextIt->size = 0; // mark for removal with std::remove_if - } - } - } - - const ChunkIterator newEnd = std::remove_if(std::begin(m_chunks), - std::end(m_chunks), - [](const Chunk& chunk) -> bool - { - return chunk.size == 0; - }); - m_chunks.erase(newEnd, std::end(m_chunks)); - } -} diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 915c4d6c9..7107411a6 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -74,7 +74,6 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS using Childrens = std::tuple; @@ -128,6 +127,26 @@ namespace samurai return Base::empty_default_impl(); } + template + inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + { + static_for<0, nIntervals>::apply( + [this, n_traversers, d_ic](const auto i) -> void + { + std::get(m_sets).init_get_traverser_work(n_traversers, d_ic); + }); + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + { + static_for<0, nIntervals>::apply( + [this, d_ic](const auto i) -> void + { + std::get(m_sets).clear_get_traverser_work(d_ic); + }); + } + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 2966532d8..fd4562a28 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -5,10 +5,11 @@ #include "../samurai_config.hpp" #include "../static_algorithm.hpp" -#include "memory_pool.hpp" #include "set_base.hpp" #include "traversers/projection_traverser.hpp" +#include + namespace samurai { @@ -41,24 +42,22 @@ namespace samurai using child_traverser_t = typename Set::template traverser_t; template - using array_of_child_traverser_offset_range_t = std::vector>::OffsetRange>; + using array_of_child_traverser_t = std::vector>; - using Type = std::tuple...>; + using Type = std::tuple...>; }; } // namespace detail template class Projection : public SetBase> { - using Self = Projection; - using OffsetRangeWork = detail::ProjectionWork>::Type; + using Self = Projection; + using ChildTraverserArray = detail::ProjectionWork>::Type; public: SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS - Projection(const Set& set, const std::size_t level) : m_set(set) , m_level(level) @@ -93,22 +92,6 @@ namespace samurai { } - ~Projection() - { - static_for<0, Base::dim>::apply( - [this](const auto d) - { - using Work = MemoryPool>; - - auto& work = Work::getInstance(); - - for (auto& offset_range : std::get(m_work_offsetRanges)) - { - work.freeChunk(offset_range); - } - }); - } - inline std::size_t level_impl() const { return m_level; @@ -124,62 +107,72 @@ namespace samurai return m_set.empty(); } - template - inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const + template + inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const { - using Work = MemoryPool>; + const std::size_t my_work_size_per_traverser = (m_projectionType == ProjectionType::COARSEN and d != Base::dim - 1) + ? (1 << m_shift) + : 1; + const std::size_t my_work_size = n_traversers * my_work_size_per_traverser; - Work& work = Work::getInstance(); + auto& childTraversers = std::get(m_work_childTraversers); + childTraversers.clear(); + childTraversers.reserve(my_work_size); - auto& offsetRange = std::get(m_work_offsetRanges); + m_set.init_get_traverser_work(my_work_size, d_ic); + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + { + auto& childTraversers = std::get(m_work_childTraversers); + + childTraversers.clear(); + + m_set.clear_get_traverser_work(d_ic); + } + + template + inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const + { + auto& childTraversers = std::get(m_work_childTraversers); if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != Base::dim - 1) { - const auto set_traversers_offsets = work.requestChunk(1 << m_shift); - auto end_offset = set_traversers_offsets.first; + const std::size_t old_capacity = childTraversers.capacity(); const value_t ymin = _index[d] << m_shift; const value_t ymax = (_index[d] + 1) << m_shift; xt::xtensor_fixed> index(_index << m_shift); + const auto childTraversers_begin = childTraversers.end(); + for (index[d] = ymin; index[d] != ymax; ++index[d]) { - std::construct_at(work.getPtr(end_offset), m_set.get_traverser(index, d_ic)); - if (work.at(end_offset).is_empty()) - { - std::destroy_at(work.getPtr(end_offset)); - } - else + childTraversers.push_back(m_set.get_traverser(index, d_ic)); + if (childTraversers.back().is_empty()) { - ++end_offset; + childTraversers.pop_back(); } } - offsetRange.push_back(set_traversers_offsets); + assert(childTraversers.capacity() == old_capacity); - return traverser_t(set_traversers_offsets.first, end_offset, m_shift); + return traverser_t(childTraversers_begin, childTraversers.end(), m_shift); } else { - const auto set_traversers_offsets = work.requestChunk(1); - std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index << m_shift, d_ic)); - - offsetRange.push_back(set_traversers_offsets); - - return traverser_t(set_traversers_offsets.first, m_projectionType, m_shift); + childTraversers.push_back(m_set.get_traverser(_index << m_shift, d_ic)); + return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } else { - const auto set_traversers_offsets = work.requestChunk(1); - std::construct_at(work.getPtr(set_traversers_offsets.first), m_set.get_traverser(_index >> m_shift, d_ic)); - - offsetRange.push_back(set_traversers_offsets); - - return traverser_t(set_traversers_offsets.first, m_projectionType, m_shift); + childTraversers.push_back(m_set.get_traverser(_index >> m_shift, d_ic)); + return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } @@ -190,7 +183,7 @@ namespace samurai ProjectionType m_projectionType; std::size_t m_shift; - mutable OffsetRangeWork m_work_offsetRanges; + mutable ChildTraverserArray m_work_childTraversers; }; } // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 9026f92fe..c8dee2bb3 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -73,6 +73,18 @@ namespace samurai return derived_cast().empty_impl(); } + template + inline void init_get_traverser_work(const std::size_t n_traversers, std::integral_constant d_ic) const + { + derived_cast().init_get_traverser_work_impl(n_traversers, d_ic); + } + + template + inline void clear_get_traverser_work(std::integral_constant d_ic) const + { + derived_cast().clear_get_traverser_work_impl(d_ic); + } + template inline traverser_t get_traverser(const index_t& index, std::integral_constant d_ic) const { @@ -122,6 +134,8 @@ namespace samurai { using current_interval_t = typename traverser_t::current_interval_t; + init_get_traverser_work(1, d_ic); + for (traverser_t traverser = get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) { current_interval_t interval = traverser.current_interval(); @@ -141,6 +155,9 @@ namespace samurai } } } + + clear_get_traverser_work(d_ic); + return true; } }; @@ -154,8 +171,6 @@ namespace samurai using interval_t = typename Base::interval_t; \ using value_t = typename Base::value_t; -#define SAMURAI_SET_CONSTEXPRS static constexpr std::size_t dim = Base::dim; - template struct IsSet : std::bool_constant, T>::value> { diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 3a0ef5dbf..208774513 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -37,7 +37,6 @@ namespace samurai public: SAMURAI_SET_TYPEDEFS - //~ SAMURAI_SET_CONSTEXPRS using translation_t = xt::xtensor_fixed>; @@ -63,6 +62,18 @@ namespace samurai return m_set.empty(); } + template + inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + { + m_set.init_get_traverser_work(n_traversers, d_ic); + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + { + m_set.clear_get_traverser_work(d_ic); + } + template inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const { diff --git a/include/samurai/subset/traversers/expansion_traverser.hpp b/include/samurai/subset/traversers/expansion_traverser.hpp index 524a71a49..947369935 100644 --- a/include/samurai/subset/traversers/expansion_traverser.hpp +++ b/include/samurai/subset/traversers/expansion_traverser.hpp @@ -29,14 +29,10 @@ namespace samurai SAMURAI_SET_TRAVERSER_TYPEDEFS - using SetTraverserIterator = typename std::vector::iterator; - using SetTraverserOffsetRange = MemoryPool::OffsetRange; - using SetTraverserOffset = MemoryPool::Distance; - - ExpansionTraverser(const SetTraverserOffset first_set_traverser_offset, - const SetTraverserOffset bound_set_traverser_offset, - const value_t expansion) - : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) + using SetTraverserIterator = typename std::vector::iterator; + + ExpansionTraverser(SetTraverserIterator begin_set_traverser, SetTraverserIterator end_set_traverser, const value_t expansion) + : m_set_traversers(begin_set_traverser, end_set_traverser) , m_expansion(expansion) { assert(m_expansion > 0); @@ -50,14 +46,11 @@ namespace samurai inline void next_interval_impl() { - auto& memory_pool = MemoryPool::getInstance(); - m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + for (const SetTraverser& set_traverser : m_set_traversers) { - const SetTraverser& set_traverser = memory_pool.at(offset); if (!set_traverser.is_empty() && (set_traverser.current_interval().start - m_expansion < m_current_interval.start)) { m_current_interval.start = set_traverser.current_interval().start - m_expansion; @@ -71,18 +64,16 @@ namespace samurai { is_done = true; // advance set traverses that are behind current interval - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + for (SetTraverser& set_traverser : m_set_traversers) { - SetTraverser& set_traverser = memory_pool.at(offset); while (!set_traverser.is_empty() && set_traverser.current_interval().end + m_expansion <= m_current_interval.end) { set_traverser.next_interval(); } } // try to find a new end - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + for (const SetTraverser& set_traverser : m_set_traversers) { - const SetTraverser& set_traverser = memory_pool.at(offset); // there is an overlap if (!set_traverser.is_empty() && set_traverser.current_interval().start - m_expansion <= m_current_interval.end) { @@ -100,9 +91,10 @@ namespace samurai private: - SetTraverserOffsetRange m_set_traverser_offsets; + std::span m_set_traversers; value_t m_expansion; interval_t m_current_interval; + bool m_isEmpty; }; } // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 75353777b..3f71e1f71 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -3,8 +3,6 @@ #pragma once -#include "../fixed_capacity_array.hpp" -#include "../memory_pool.hpp" #include "set_traverser_base.hpp" namespace samurai @@ -30,46 +28,40 @@ namespace samurai template class ProjectionTraverser : public SetTraverserBase> { - using Self = ProjectionTraverser; - - using SetTraverserOffsetRange = MemoryPool::OffsetRange; - using SetTraverserOffset = MemoryPool::Distance; + using Self = ProjectionTraverser; + using SetTraverserIterator = typename std::vector::iterator; public: SAMURAI_SET_TRAVERSER_TYPEDEFS - ProjectionTraverser(SetTraverserOffset set_traverser_offset, const ProjectionType projectionType, const std::size_t shift) - : m_set_traverser_offsets(set_traverser_offset, set_traverser_offset + 1) + ProjectionTraverser(SetTraverserIterator set_traverser, const ProjectionType projectionType, const std::size_t shift) + : m_set_traversers(set_traverser, set_traverser + 1) , m_projectionType(projectionType) , m_shift(shift) - , m_isEmpty(MemoryPool::getInstance().at(set_traverser_offset).is_empty()) + , m_isEmpty(set_traverser->is_empty()) { - auto& memory_pool = MemoryPool::getInstance(); - if (!m_isEmpty) { - SetTraverser& set_traverser = memory_pool.at(set_traverser_offset); - if (m_projectionType == ProjectionType::COARSEN) { - m_current_interval.start = coarsen_start(set_traverser.current_interval()); - m_current_interval.end = coarsen_end(set_traverser.current_interval()); + m_current_interval.start = coarsen_start(m_set_traversers[0].current_interval()); + m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); - set_traverser.next_interval(); + m_set_traversers[0].next_interval(); // when coarsening, two disjoint intervals may be merged. // we need to check if the next_interval overlaps - for (; !set_traverser.is_empty() && coarsen_start(set_traverser.current_interval()) <= m_current_interval.end; - set_traverser.next_interval()) + for (; !m_set_traversers[0].is_empty() && coarsen_start(m_set_traversers[0].current_interval()) <= m_current_interval.end; + m_set_traversers[0].next_interval()) { - m_current_interval.end = coarsen_end(set_traverser.current_interval()); + m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); } } else { - m_current_interval.start = set_traverser.current_interval().start << shift; - m_current_interval.end = set_traverser.current_interval().end << shift; + m_current_interval.start = m_set_traversers[0].current_interval().start << shift; + m_current_interval.end = m_set_traversers[0].current_interval().end << shift; } } } @@ -77,10 +69,8 @@ namespace samurai /* * This constructor only works for coarsening */ - ProjectionTraverser(const SetTraverserOffset first_set_traverser_offset, - const SetTraverserOffset bound_set_traverser_offset, - const std::size_t shift) - : m_set_traverser_offsets(first_set_traverser_offset, bound_set_traverser_offset) + ProjectionTraverser(SetTraverserIterator begin_set_traversers, SetTraverserIterator end_set_traversers, const std::size_t shift) + : m_set_traversers(begin_set_traversers, end_set_traversers) , m_projectionType(ProjectionType::COARSEN) , m_shift(shift) { @@ -100,14 +90,12 @@ namespace samurai } else { - SetTraverser& set_traverser = MemoryPool::getInstance().at(m_set_traverser_offsets.first); - - set_traverser.next_interval(); - m_isEmpty = set_traverser.is_empty(); + m_set_traversers[0].next_interval(); + m_isEmpty = m_set_traversers[0].is_empty(); if (!m_isEmpty) { - m_current_interval.start = set_traverser.current_interval().start << m_shift; - m_current_interval.end = set_traverser.current_interval().end << m_shift; + m_current_interval.start = m_set_traversers[0].current_interval().start << m_shift; + m_current_interval.end = m_set_traversers[0].current_interval().end << m_shift; } } } @@ -121,14 +109,10 @@ namespace samurai inline void next_interval_coarsen() { - auto& memory_pool = MemoryPool::getInstance(); - m_current_interval.start = std::numeric_limits::max(); // We find the start of the interval, i.e. the smallest set_traverser.current_interval().start >> m_shift - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + for (const SetTraverser& set_traverser : m_set_traversers) { - const SetTraverser& set_traverser = memory_pool.at(offset); - if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) < m_current_interval.start)) { m_current_interval.start = coarsen_start(set_traverser.current_interval()); @@ -142,20 +126,16 @@ namespace samurai { is_done = true; // advance set traverses that are behind current interval - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + for (SetTraverser& set_traverser : m_set_traversers) { - SetTraverser& set_traverser = memory_pool.at(offset); - while (!set_traverser.is_empty() && (coarsen_end(set_traverser.current_interval()) <= m_current_interval.end)) { set_traverser.next_interval(); } } // try to find a new end - for (auto offset = m_set_traverser_offsets.first; offset != m_set_traverser_offsets.bound; ++offset) + for (const SetTraverser& set_traverser : m_set_traversers) { - const SetTraverser& set_traverser = memory_pool.at(offset); - // there is an overlap if (!set_traverser.is_empty() && (coarsen_start(set_traverser.current_interval()) <= m_current_interval.end)) { @@ -177,7 +157,7 @@ namespace samurai return ((interval.end - 1) >> m_shift) + 1; } - SetTraverserOffsetRange m_set_traverser_offsets; + std::span m_set_traversers; ProjectionType m_projectionType; std::size_t m_shift; interval_t m_current_interval; diff --git a/include/samurai/subset/work.hpp b/include/samurai/subset/work.hpp deleted file mode 100644 index 929a89fa5..000000000 --- a/include/samurai/subset/work.hpp +++ /dev/null @@ -1,2 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause From a575628b056bc1209fb0b6f9e6cddac11a59a2fa Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Mon, 6 Oct 2025 15:29:16 +0200 Subject: [PATCH 15/28] added a 'list of interval' option for projection --- include/samurai/interval.hpp | 3 +- include/samurai/list_of_intervals.hpp | 5 + include/samurai/samurai_config.hpp | 2 + include/samurai/subset/projection.hpp | 8 +- include/samurai/subset/projection_loi.hpp | 202 ++++++++++++++++++ include/samurai/subset/projection_type.hpp | 13 ++ include/samurai/subset/set_base.hpp | 13 +- .../last_dim_projection_loi_traverser.hpp | 118 ++++++++++ .../traversers/projection_loi_traverser.hpp | 87 ++++++++ .../traversers/projection_traverser.hpp | 7 +- tests/test_subset.cpp | 5 + 11 files changed, 448 insertions(+), 15 deletions(-) create mode 100644 include/samurai/subset/projection_loi.hpp create mode 100644 include/samurai/subset/projection_type.hpp create mode 100644 include/samurai/subset/traversers/last_dim_projection_loi_traverser.hpp create mode 100644 include/samurai/subset/traversers/projection_loi_traverser.hpp diff --git a/include/samurai/interval.hpp b/include/samurai/interval.hpp index 97ef0cd5d..c84a60263 100644 --- a/include/samurai/interval.hpp +++ b/include/samurai/interval.hpp @@ -362,7 +362,8 @@ namespace samurai template inline bool operator==(const Interval& i1, const Interval& i2) { - return !(i1.start != i2.start || i1.end != i2.end || i1.step != i2.step || i1.index != i2.index); + //~ return !(i1.start != i2.start || i1.end != i2.end || i1.step != i2.step || i1.index != i2.index); + return !(i1.start != i2.start || i1.end != i2.end || i1.step != i2.step); } template diff --git a/include/samurai/list_of_intervals.hpp b/include/samurai/list_of_intervals.hpp index d3889f847..ee8d90e12 100644 --- a/include/samurai/list_of_intervals.hpp +++ b/include/samurai/list_of_intervals.hpp @@ -62,6 +62,11 @@ namespace samurai void add_point(value_t point); void add_interval(const interval_t& interval); + + void clear() + { + std::forward_list>::clear(); + } }; //////////////////////////////////// diff --git a/include/samurai/samurai_config.hpp b/include/samurai/samurai_config.hpp index b4394f61a..ba0ebd361 100644 --- a/include/samurai/samurai_config.hpp +++ b/include/samurai/samurai_config.hpp @@ -20,6 +20,8 @@ namespace samurai static constexpr std::size_t graduation_width = 1; static constexpr std::size_t prediction_order = 1; + static constexpr bool prediction_with_list_of_intervals = true; + using index_t = signed long long int; using value_t = int; using interval_t = Interval; diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index fd4562a28..d651e25e2 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -8,8 +8,6 @@ #include "set_base.hpp" #include "traversers/projection_traverser.hpp" -#include - namespace samurai { @@ -143,14 +141,14 @@ namespace samurai { const std::size_t old_capacity = childTraversers.capacity(); - const value_t ymin = _index[d] << m_shift; - const value_t ymax = (_index[d] + 1) << m_shift; + const value_t ymin = _index[d] << m_shift; + const value_t ybound = (_index[d] + 1) << m_shift; xt::xtensor_fixed> index(_index << m_shift); const auto childTraversers_begin = childTraversers.end(); - for (index[d] = ymin; index[d] != ymax; ++index[d]) + for (index[d] = ymin; index[d] != ybound; ++index[d]) { childTraversers.push_back(m_set.get_traverser(index, d_ic)); if (childTraversers.back().is_empty()) diff --git a/include/samurai/subset/projection_loi.hpp b/include/samurai/subset/projection_loi.hpp new file mode 100644 index 000000000..2e13c6676 --- /dev/null +++ b/include/samurai/subset/projection_loi.hpp @@ -0,0 +1,202 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../samurai_config.hpp" +#include "../static_algorithm.hpp" +#include "set_base.hpp" +#include "traversers/last_dim_projection_loi_traverser.hpp" +#include "traversers/projection_loi_traverser.hpp" + +#include + +namespace samurai +{ + + template + class ProjectionLOI; + + template + struct SetTraits> + { + static_assert(IsSet::value); + + template + using child_traverser_t = typename Set::template traverser_t; + + template + using traverser_t = std::conditional_t>, + ProjectionLOITraverser>>; + + static constexpr std::size_t dim() + { + return Set::dim; + } + }; + + namespace detail + { + template + struct ProjectionLOIWork; + + template + struct ProjectionLOIWork> + { + template + using child_traverser_t = typename Set::template traverser_t; + + template + using work_t = ListOfIntervals::value_t>; + + using Type = std::tuple...>; + }; + } // namespace detail + + template + class ProjectionLOI : public SetBase> + { + using Self = ProjectionLOI; + using ListOfIntervals = detail::ProjectionLOIWork>::Type; + + public: + + SAMURAI_SET_TYPEDEFS + + using Index = xt::xtensor_fixed>; + + ProjectionLOI(const Set& set, const std::size_t level) + : m_set(set) + , m_level(level) + { + if (m_level < m_set.level()) + { + m_projectionType = ProjectionType::COARSEN; + m_shift = m_set.level() - m_level; + } + else + { + m_projectionType = ProjectionType::REFINE; + m_shift = m_level - m_set.level(); + } + } + + // we need to define a custom copy and move constructor because + // we do not want to copy m_work_offsetRanges + ProjectionLOI(const ProjectionLOI& other) + : m_set(other.m_set) + , m_level(other.m_level) + , m_projectionType(other.m_projectionType) + , m_shift(other.m_shift) + { + } + + ProjectionLOI(ProjectionLOI&& other) + : m_set(std::move(other.m_set)) + , m_level(std::move(other.m_level)) + , m_projectionType(std::move(other.m_projectionType)) + , m_shift(std::move(other.m_shift)) + { + } + + inline std::size_t level_impl() const + { + return m_level; + } + + inline bool exist_impl() const + { + return m_set.exist(); + } + + inline bool empty_impl() const + { + return m_set.empty(); + } + + template + inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + { + assert(n_traversers == 1); + + m_set.init_get_traverser_work(n_traversers, d_ic); + } + + template + inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + { + m_set.clear_get_traverser_work(d_ic); + } + + template + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + { + auto& listOfIntervals = std::get(m_work_listOfIntervals); + listOfIntervals.clear(); + + if (m_projectionType == ProjectionType::COARSEN) + { + if constexpr (d != Base::dim - 1) + { + Index index_min(index << m_shift); + Index index_max((index + 1) << m_shift); + + Index index_rec; + fill_list_of_interval_rec(index_min, index_max, index_rec, d_ic, std::integral_constant{}); + + return traverser_t(m_set.get_traverser(index << m_shift, d_ic), listOfIntervals.cbegin(), listOfIntervals.cend()); + } + else + { + return traverser_t(m_set.get_traverser(index << m_shift, d_ic), m_projectionType, m_shift); + } + } + else + { + return traverser_t(m_set.get_traverser(index >> m_shift, d_ic), m_projectionType, m_shift); + } + } + + private: + + template + inline void fill_list_of_interval_rec(const Index& index_min, + const Index& index_max, + index_t& index, + std::integral_constant d_ic, + std::integral_constant dCur_ic) const + { + using child_traverser_t = typename Set::template traverser_t; + using child_current_interval_t = typename child_traverser_t::current_interval_t; + + for (child_traverser_t traverser = m_set.get_traverser(index, dCur_ic); !traverser.is_empty(); traverser.next_interval()) + { + child_current_interval_t interval = traverser.current_interval(); + + if constexpr (dCur == d) + { + std::get(m_work_listOfIntervals).add_interval(interval >> m_shift); + } + else + { + const auto index_start = std::max(interval.start, index_min[dCur - 1]); + const auto index_end = std::min(interval.end, index_max[dCur - 1]); + + for (index[dCur - 1] = index_start; index[dCur - 1] < index_end; ++index[dCur - 1]) + { + fill_list_of_interval_rec(index_min, index_max, index, d_ic, std::integral_constant{}); + } + } + } + } + + Set m_set; + std::size_t m_level; + ProjectionType m_projectionType; + std::size_t m_shift; + + mutable ListOfIntervals m_work_listOfIntervals; + }; + +} // namespace samurai diff --git a/include/samurai/subset/projection_type.hpp b/include/samurai/subset/projection_type.hpp new file mode 100644 index 000000000..5489a0c0b --- /dev/null +++ b/include/samurai/subset/projection_type.hpp @@ -0,0 +1,13 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +namespace samurai +{ + enum class ProjectionType + { + COARSEN, + REFINE + }; +} // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index c8dee2bb3..1f0aff9ca 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -7,6 +7,7 @@ #include +#include "../samurai_config.hpp" #include "traversers/set_traverser_base.hpp" namespace samurai @@ -24,6 +25,9 @@ namespace samurai template class Projection; + template + class ProjectionLOI; + template void apply(const SetBase& set, Func&& func); @@ -46,6 +50,8 @@ namespace samurai using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; + using ProjectionMethod = std::conditional_t, Projection>; + static constexpr std::size_t dim = DerivedTraits::dim(); const Derived& derived_cast() const @@ -91,7 +97,7 @@ namespace samurai return derived_cast().get_traverser_impl(index, d_ic); } - inline Projection on(const std::size_t level); + inline ProjectionMethod on(const std::size_t level); template void operator()(Func&& func) const @@ -185,14 +191,15 @@ namespace samurai } // namespace samurai #include "projection.hpp" +#include "projection_loi.hpp" namespace samurai { template - Projection SetBase::on(const std::size_t level) + auto SetBase::on(const std::size_t level) -> ProjectionMethod { - return Projection(derived_cast(), level); + return ProjectionMethod(derived_cast(), level); } } diff --git a/include/samurai/subset/traversers/last_dim_projection_loi_traverser.hpp b/include/samurai/subset/traversers/last_dim_projection_loi_traverser.hpp new file mode 100644 index 000000000..07847cc03 --- /dev/null +++ b/include/samurai/subset/traversers/last_dim_projection_loi_traverser.hpp @@ -0,0 +1,118 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_traverser_base.hpp" + +namespace samurai +{ + template + class LastDimProjectionLOITraverser; + + template + struct SetTraverserTraits> + { + static_assert(IsSetTraverser::value); + + using interval_t = typename SetTraverser::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class LastDimProjectionLOITraverser : public SetTraverserBase> + { + using Self = LastDimProjectionLOITraverser; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + LastDimProjectionLOITraverser(const SetTraverser& set_traverser, const ProjectionType projectionType, const std::size_t shift) + : m_set_traverser(set_traverser) + , m_projectionType(projectionType) + , m_shift(shift) + , m_isEmpty(set_traverser.is_empty()) + { + if (m_projectionType == ProjectionType::COARSEN) + { + next_interval_coarsen(); + } + else if (!m_isEmpty) + { + m_current_interval.start = m_set_traverser.current_interval().start << shift; + m_current_interval.end = m_set_traverser.current_interval().end << shift; + } + } + + inline bool is_empty_impl() const + { + return m_isEmpty; + } + + inline void next_interval_impl() + { + if (m_projectionType == ProjectionType::COARSEN) + { + next_interval_coarsen(); + } + else + { + m_set_traverser.next_interval(); + m_isEmpty = m_set_traverser.is_empty(); + if (!m_isEmpty) + { + m_current_interval.start = m_set_traverser.current_interval().start << m_shift; + m_current_interval.end = m_set_traverser.current_interval().end << m_shift; + } + } + } + + inline current_interval_t current_interval_impl() const + { + return m_current_interval; + } + + private: + + inline void next_interval_coarsen() + { + if (!m_set_traverser.is_empty()) + { + m_current_interval.start = coarsen_start(m_set_traverser.current_interval()); + m_current_interval.end = coarsen_end(m_set_traverser.current_interval()); + + m_set_traverser.next_interval(); + + // when coarsening, two disjoint intervals may be merged. + // we need to check if the next_interval overlaps + for (; !m_set_traverser.is_empty() && coarsen_start(m_set_traverser.current_interval()) <= m_current_interval.end; + m_set_traverser.next_interval()) + { + m_current_interval.end = coarsen_end(m_set_traverser.current_interval()); + } + } + else + { + m_isEmpty = true; + } + } + + inline value_t coarsen_start(const interval_t& interval) const + { + return interval.start >> m_shift; + } + + inline value_t coarsen_end(const interval_t& interval) const + { + return ((interval.end - 1) >> m_shift) + 1; + } + + SetTraverser m_set_traverser; + ProjectionType m_projectionType; + std::size_t m_shift; + interval_t m_current_interval; + bool m_isEmpty; + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/projection_loi_traverser.hpp b/include/samurai/subset/traversers/projection_loi_traverser.hpp new file mode 100644 index 000000000..32afbc79f --- /dev/null +++ b/include/samurai/subset/traversers/projection_loi_traverser.hpp @@ -0,0 +1,87 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../../list_of_intervals.hpp" +#include "set_traverser_base.hpp" + +namespace samurai +{ + template + class ProjectionLOITraverser; + + template + struct SetTraverserTraits> + { + static_assert(IsSetTraverser::value); + + using interval_t = typename SetTraverser::interval_t; + using current_interval_t = interval_t; + }; + + template + class ProjectionLOITraverser : public SetTraverserBase> + { + using Self = ProjectionLOITraverser; + using SetTraverserIterator = typename ListOfIntervals::const_iterator; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + ProjectionLOITraverser(SetTraverser set_traverser, const ProjectionType projectionType, const std::size_t shift) + : m_set_traverser(set_traverser) + , m_shift(shift) + , m_projectionType(ProjectionType::REFINE) + { + assert(projectionType == m_projectionType); + } + + ProjectionLOITraverser(SetTraverser set_traverser, SetTraverserIterator first_interval, SetTraverserIterator bound_interval) + : m_set_traverser(set_traverser) + , m_first_interval(first_interval) + , m_bound_interval(bound_interval) + , m_projectionType(ProjectionType::COARSEN) + { + } + + inline bool is_empty_impl() const + { + if (m_projectionType == ProjectionType::COARSEN) + { + return m_first_interval == m_bound_interval; + } + else + { + return m_set_traverser.is_empty(); + } + } + + inline void next_interval_impl() + { + if (m_projectionType == ProjectionType::COARSEN) + { + ++m_first_interval; + } + else + { + m_set_traverser.next_interval(); + } + } + + inline current_interval_t current_interval_impl() const + { + return (m_projectionType == ProjectionType::COARSEN) ? *m_first_interval : m_set_traverser.current_interval() << m_shift; + } + + private: + + SetTraverser m_set_traverser; // only used when refining + std::size_t m_shift; // only used when refining + SetTraverserIterator m_first_interval; // only use when coarsening + SetTraverserIterator m_bound_interval; // only use when coarsening + ProjectionType m_projectionType; + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 3f71e1f71..267e0df1e 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -3,16 +3,11 @@ #pragma once +#include "../projection_type.hpp" #include "set_traverser_base.hpp" namespace samurai { - enum class ProjectionType - { - COARSEN, - REFINE - }; - template class ProjectionTraverser; diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 3171b246c..e1f0c256a 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -458,6 +458,7 @@ namespace samurai {5, {5, 33}} }; std::size_t ie = 0; + fmt::print("====================================================\n"); apply(union_(ca_1[7], ca_2[7]).on(6), [&](auto& i, auto& index) { @@ -1304,6 +1305,10 @@ namespace samurai ca = {cl, true}; + std::cout << self(ca[4]).on(3).to_lca() << std::endl; + + fmt::print("===============================================\n"); + // Test self-similarity at different scales bool found = false; apply(intersection(ca[3], self(ca[4]).on(3)), From 35cfcbfbc6a4092532b6ad681ebb984146363e61 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Tue, 7 Oct 2025 17:40:07 +0200 Subject: [PATCH 16/28] started to add traverser ranges --- include/samurai/samurai_config.hpp | 2 +- include/samurai/subset/nary_set_operator.hpp | 1 + .../range_traversers/lca_traverser_range.hpp | 124 +++++++++++++++ .../lca_traverser_range_item.hpp | 57 +++++++ .../set_traverser_range_base.hpp | 60 ++++++++ .../translation_traverser_range.hpp | 121 +++++++++++++++ .../union_traverser_range.hpp | 143 ++++++++++++++++++ .../subset/traversers/set_traverser_base.hpp | 3 - .../subset/traversers/union_traverser.hpp | 2 +- 9 files changed, 508 insertions(+), 5 deletions(-) create mode 100644 include/samurai/subset/range_traversers/lca_traverser_range.hpp create mode 100644 include/samurai/subset/range_traversers/lca_traverser_range_item.hpp create mode 100644 include/samurai/subset/range_traversers/set_traverser_range_base.hpp create mode 100644 include/samurai/subset/range_traversers/translation_traverser_range.hpp create mode 100644 include/samurai/subset/range_traversers/union_traverser_range.hpp diff --git a/include/samurai/samurai_config.hpp b/include/samurai/samurai_config.hpp index ba0ebd361..f5ac59a5a 100644 --- a/include/samurai/samurai_config.hpp +++ b/include/samurai/samurai_config.hpp @@ -20,7 +20,7 @@ namespace samurai static constexpr std::size_t graduation_width = 1; static constexpr std::size_t prediction_order = 1; - static constexpr bool prediction_with_list_of_intervals = true; + static constexpr bool prediction_with_list_of_intervals = false; using index_t = signed long long int; using value_t = int; diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 7107411a6..2df60d937 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -3,6 +3,7 @@ #pragma once +#include "nary_set_operator_types.hpp" #include "set_base.hpp" #include "traversers/difference_id_traverser.hpp" #include "traversers/difference_traverser.hpp" diff --git a/include/samurai/subset/range_traversers/lca_traverser_range.hpp b/include/samurai/subset/range_traversers/lca_traverser_range.hpp new file mode 100644 index 000000000..7a627a6a9 --- /dev/null +++ b/include/samurai/subset/range_traversers/lca_traverser_range.hpp @@ -0,0 +1,124 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include +#include + +#include "lca_traverser_range_item.hpp" +#include "set_traverser_range_base.hpp" + +namespace samurai +{ + + template + class LevelCellArray; + + template + class LCATraverserRange; + + template + struct SetTraverserRangeTraits> + { + static_assert(std::same_as, LCA>); + + using interval_iterator = typename std::vector::const_iterator; + using offset_iterator = typename std::vector::iterator; + + template + class _Iterator + { + public: + + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = LCATraverserRangeItem; + using reference = LCATraverserRangeItem; + + _Iterator(const interval_iterator first_interval, const offset_iterator offset) + : m_first_interval(first_interval) + , m_offset(offset) + { + } + + reference operator*() const + { + return reference(m_first_interval, m_offset); + } + + _Iterator& operator++() + { + ++m_offset; + return *this; + } + + _Iterator operator++(int) + { + _Iterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const _Iterator& a, const _Iterator& b) + { + return a.m_first_interval == b.m_first_interval and a.m_offset == b.m_offset; + }; + + friend bool operator!=(const _Iterator& a, const _Iterator& b) + { + return a.m_ptr != b.m_ptr or a.m_offset != b.m_offset; + }; + + private: + + interval_iterator m_first_interval; + offset_iterator m_offset; + }; + + using Iterator = _Iterator; + using const_Iterator = _Iterator; + }; + + template + class LCATraverserRange : public SetTraverserRangeBase> + { + using Self = LCATraverserRange : public + : SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS using interval_iterator = typename std::vector::const_iterator; + using offset_iterator = typename std::vector::iterator; + + LCATraverserRange(const interval_iterator first_interval, const offset_iterator first_offsets, const offset_iterator last_offsets) + : m_first_interval(first_interval) + , m_first_offsets(first_offsets) + , m_last_offsets(last_offsets) + { + } + + Iterator begin_impl() + { + return Iterator(m_first_interval, m_first_offsets); + } + + Iterator end_impl() + { + return Iterator(m_first_interval, std::prev(m_last_offsets)); + } + + const_Iterator begin_impl() const + { + return const_Iterator(m_first_interval, m_first_offsets); + } + + const_Iterator end_impl() const + { + return const_Iterator(m_first_interval, std::prev(m_last_offsets)); + } + + private: + + interval_iterator m_first_interval; + offset_iterator m_first_offsets; + offset_iterator m_last_offsets; + }; + +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp b/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp new file mode 100644 index 000000000..28ba05804 --- /dev/null +++ b/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp @@ -0,0 +1,57 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include +#include + +namespace samurai +{ + + template + class LevelCellArray; + + template + class LCATraverserRangeItem : public SetTraverserBase> + { + using Self = LCATraverserRangeItem; + + public: + + SAMURAI_SET_TRAVERSER_TYPEDEFS + + using interval_iterator = typename std::vector::const_iterator; + using offset_iterator = typename std::vector::iterator; + + LCATraverserRangeItem(const interval_iterator first_interval, const offset_iterator offset) + : m_first_interval(first_interval) + , m_offset(*offset) + , m_offset_bound(*(offset + 1)) + { + } + + inline bool is_empty_impl() const + { + return m_offset == m_offset_bound; + } + + inline void next_interval_impl() + requires(!isConst) + { + ++m_offset; + } + + inline current_interval_t current_interval_impl() const + { + return *(m_first_interval + m_offset); + } + + private: + + interval_iterator m_first_interval; + std::size_t& m_offset; + std::size_t m_offset_bound; + }; + +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/set_traverser_range_base.hpp b/include/samurai/subset/range_traversers/set_traverser_range_base.hpp new file mode 100644 index 000000000..415060cde --- /dev/null +++ b/include/samurai/subset/range_traversers/set_traverser_range_base.hpp @@ -0,0 +1,60 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include +#include + +namespace samurai +{ + template + struct SetTraverserRangeTraits; + + template + class SetTraverserRangeBase + { + public: + + using DerivedTraits = SetTraverserRangeTraits; + + using Iterator = typename DerivedTraits::Iterator; + using const_Iterator = typename DerivedTraits::const_Iterator; + + const Derived& derived_cast() const + { + return static_cast(*this); + } + + Derived& derived_cast() + { + return static_cast(*this); + } + + Iterator begin() + { + derived_cast().begin_impl(); + } + + const_Iterator begin() const + { + derived_cast().begin_impl(); + } + + const_Iterator cbegin() const + { + derived_cast().begin_impl(); + } + }; + + template + struct IsSetTraverserRange : std::bool_constant, T>::value> + { + }; + +#define SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS \ + using Base = SetTraverserBase; \ + using Iterator = typename Base::Iterator; \ + using const_Iterator = typename Base::const_Iterator; + +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/translation_traverser_range.hpp b/include/samurai/subset/range_traversers/translation_traverser_range.hpp new file mode 100644 index 000000000..5f9e4409d --- /dev/null +++ b/include/samurai/subset/range_traversers/translation_traverser_range.hpp @@ -0,0 +1,121 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "set_traverser_range_base.hpp" + +namespace samurai +{ + + template + class TranslationTraverserRange; + + template + struct SetTraverserRangeTraits> + { + static_assert(IsSetTraverserRange::value); + + using ChildIterator = typename SetTraverserRange::Iterator; + using const_ChildIterator = typename SetTraverserRange::const_Iterator; + + using Translation = typename ChildIterator::value_type::value_type; + + template + class _Iterator + { + public: + + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = TranslationTraverser; + using reference = value_type; + + _Iterator(const Inner_Iterator inner_Iterator, const Translation& translation) + : m_innerIterator(inner_Iterator) + , m_translation(translation) + { + } + + reference operator*() const + { + return reference(*m_innerIterator, m_translation); + } + + _Iterator& operator++() + { + ++m_innerIterator; + return *this; + } + + _Iterator operator++(int) + { + _Iterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const _Iterator& a, const _Iterator& b) + { + return a.m_innerIterator == b.m_innerIterator; + }; + + friend bool operator!=(const _Iterator& a, const _Iterator& b) + { + return a.m_innerIterator != b.m_innerIterator; + }; + + private: + + Inner_Iterator m_innerIterator; + Translation m_translation; + }; + + using Iterator = _Iterator; + using const_Iterator = _Iterator; + }; + + template + class TranslationTraverserRange : public SetTraverserRangeBase> + { + using Self = TranslationTraverserRange; + + public: + + SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS + + using Translation = typename SetTraverserRangeTraits::Translation; + + TranslationTraverserRange(const SetTraverserRange& set_traverser_range, const Translation& translation) + : m_set_traverser_range(set_traverser_range) + , m_translation(translation) + { + } + + Iterator begin_impl() + { + return Iterator(m_set_traverser_range.begin(), m_translation); + } + + Iterator end_impl() + { + return Iterator(m_set_traverser_range.end(), m_translation); + } + + const_Iterator begin_impl() const + { + return const_Iterator(m_set_traverser_range.cbegin(), m_translation); + } + + const_Iterator end_impl() const + { + return const_Iterator(m_set_traverser_range.cend(), m_translation); + } + + private: + + SetTraverserRange m_set_traverser_range; + Translation m_translation; + }; + +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/union_traverser_range.hpp b/include/samurai/subset/range_traversers/union_traverser_range.hpp new file mode 100644 index 000000000..514838763 --- /dev/null +++ b/include/samurai/subset/range_traversers/union_traverser_range.hpp @@ -0,0 +1,143 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +namespace samurai +{ + + template + class UnionTraverserRange; + + template + struct SetTraverserRangeTraits> + { + static_assert((IsSetTraverserRange::value and ...)); + + template + class _Iterator + { + public: + + using Childrens = std::tuple; + + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = UnionTraverser; + using reference = value_type; + + static constexpr std::size_t nIntervals = std::tuple_size::value; + + _Iterator(const Inner_Iterators... inner_Iterators) + : m_inner_Iterator(inner_Iterators...) + { + } + + reference operator*() const + { + return std::apply( + [](const auto&... innerIterators) + { + return reference((*innerIterators)...); + }, + m_innerIterators); + } + + _Iterator& operator++() + { + static_for<0, nIntervals>::apply( + [this](const auto i) -> void + { + ++std::get(m_innerIterators); + }); + return *this; + } + + _Iterator operator++(int) + { + _Iterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const _Iterator& a, const _Iterator& b) + { + return a.m_inner_Iterator == b.m_inner_Iterator; + }; + + friend bool operator!=(const _Iterator& a, const _Iterator& b) + { + return a.m_inner_Iterator != b.m_inner_Iterator; + }; + + private: + + Childrens m_innerIterators; + }; + + using Iterator = _Iterator; + using const_Iterator = _Iterator; + }; + + template + class UnionTraverserRange : public SetTraverserRangeBase> + { + using Self = TranslationTraverserRange; + + public: + + SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS + + using Childrens = std::tuple; + + TranslationTraverserRange(const SetTraverserRanges&... set_traverser_ranges) + : m_set_traverser_ranges(set_traverser_ranges...) + { + } + + Iterator begin_impl() + { + return std::apply( + [](auto&... innerIterators) + { + return Iterator(innerIterators.begin()...); + }, + m_set_traverser_ranges); + } + + Iterator end_impl() + { + return std::apply( + [](auto&... innerIterators) + { + return Iterator(innerIterators.end()...); + }, + m_set_traverser_ranges); + } + + const_Iterator begin_impl() const + { + return std::apply( + [](const auto&... innerIterators) + { + return const_Iterator(innerIterators.cbegin()...); + }, + m_set_traverser_ranges); + } + + const_Iterator end_impl() const + { + return std::apply( + [](const auto&... innerIterators) + { + return const_Iterator(innerIterators.cend()...); + }, + m_set_traverser_ranges); + } + + private: + + Childrens m_set_traverser_ranges; + }; + +} // namespace samurai diff --git a/include/samurai/subset/traversers/set_traverser_base.hpp b/include/samurai/subset/traversers/set_traverser_base.hpp index 196ffce61..2d7855293 100644 --- a/include/samurai/subset/traversers/set_traverser_base.hpp +++ b/include/samurai/subset/traversers/set_traverser_base.hpp @@ -11,9 +11,6 @@ namespace samurai template struct SetTraverserTraits; - template - class SetTraverserBase; - template class SetTraverserBase { diff --git a/include/samurai/subset/traversers/union_traverser.hpp b/include/samurai/subset/traversers/union_traverser.hpp index 14b210d97..00dc22b81 100644 --- a/include/samurai/subset/traversers/union_traverser.hpp +++ b/include/samurai/subset/traversers/union_traverser.hpp @@ -34,7 +34,7 @@ namespace samurai template using IthChild = std::tuple_element::type; - static constexpr std::size_t nIntervals = std::tuple_size_v; + static constexpr std::size_t nIntervals = std::tuple_size::value; UnionTraverser(const std::array& shifts, const SetTraversers&... set_traversers) : m_set_traversers(set_traversers...) From b6bbedfcd2d700d918d61a149777da07420ce7d7 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Tue, 7 Oct 2025 17:43:16 +0200 Subject: [PATCH 17/28] started to add traverser ranges --- .../subset/range_traversers/lca_traverser_range.hpp | 10 +++++++--- .../range_traversers/lca_traverser_range_item.hpp | 2 +- .../subset/range_traversers/union_traverser_range.hpp | 10 +++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/samurai/subset/range_traversers/lca_traverser_range.hpp b/include/samurai/subset/range_traversers/lca_traverser_range.hpp index 7a627a6a9..b5037b1d3 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range.hpp +++ b/include/samurai/subset/range_traversers/lca_traverser_range.hpp @@ -83,9 +83,13 @@ namespace samurai template class LCATraverserRange : public SetTraverserRangeBase> { - using Self = LCATraverserRange : public - : SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS using interval_iterator = typename std::vector::const_iterator; - using offset_iterator = typename std::vector::iterator; + using Self = LCATraverserRange; + + public: + + SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS + using interval_iterator = typename std::vector::const_iterator; + using offset_iterator = typename std::vector::iterator; LCATraverserRange(const interval_iterator first_interval, const offset_iterator first_offsets, const offset_iterator last_offsets) : m_first_interval(first_interval) diff --git a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp b/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp index 28ba05804..4dad7b579 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp +++ b/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp @@ -13,7 +13,7 @@ namespace samurai class LevelCellArray; template - class LCATraverserRangeItem : public SetTraverserBase> + class LCATraverserRangeItem : public SetTraverserBase> { using Self = LCATraverserRangeItem; diff --git a/include/samurai/subset/range_traversers/union_traverser_range.hpp b/include/samurai/subset/range_traversers/union_traverser_range.hpp index 514838763..89a787c15 100644 --- a/include/samurai/subset/range_traversers/union_traverser_range.hpp +++ b/include/samurai/subset/range_traversers/union_traverser_range.hpp @@ -36,7 +36,7 @@ namespace samurai reference operator*() const { return std::apply( - [](const auto&... innerIterators) + [](const auto&... innerIterators) -> void { return reference((*innerIterators)...); }, @@ -98,7 +98,7 @@ namespace samurai Iterator begin_impl() { return std::apply( - [](auto&... innerIterators) + [](auto&... innerIterators) -> Iterator { return Iterator(innerIterators.begin()...); }, @@ -108,7 +108,7 @@ namespace samurai Iterator end_impl() { return std::apply( - [](auto&... innerIterators) + [](auto&... innerIterators) -> Iterator { return Iterator(innerIterators.end()...); }, @@ -118,7 +118,7 @@ namespace samurai const_Iterator begin_impl() const { return std::apply( - [](const auto&... innerIterators) + [](const auto&... innerIterators) -> const_Iterator { return const_Iterator(innerIterators.cbegin()...); }, @@ -128,7 +128,7 @@ namespace samurai const_Iterator end_impl() const { return std::apply( - [](const auto&... innerIterators) + [](const auto&... innerIterators) -> const_Iterator { return const_Iterator(innerIterators.cend()...); }, From 6bda7b47bf7520fa56b03189064af79de42d07a9 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 8 Oct 2025 15:48:12 +0200 Subject: [PATCH 18/28] range partly implemented --- .../range_traversers/box_traverser_range.hpp | 110 ++++++++++++++ .../range_traversers/lca_traverser_range.hpp | 32 ++-- .../lca_traverser_range_item.hpp | 18 ++- .../range_traversers/nary_traverser_range.hpp | 120 +++++++++++++++ .../range_traversers/nary_traverser_type.hpp | 48 ++++++ .../set_traverser_range_base.hpp | 23 ++- .../translation_traverser_range.hpp | 36 ++--- .../union_traverser_range.hpp | 143 ------------------ .../subset/traversers/box_traverser.hpp | 4 +- .../subset/traversers/lca_traverser.hpp | 1 - 10 files changed, 325 insertions(+), 210 deletions(-) create mode 100644 include/samurai/subset/range_traversers/box_traverser_range.hpp create mode 100644 include/samurai/subset/range_traversers/nary_traverser_range.hpp create mode 100644 include/samurai/subset/range_traversers/nary_traverser_type.hpp delete mode 100644 include/samurai/subset/range_traversers/union_traverser_range.hpp diff --git a/include/samurai/subset/range_traversers/box_traverser_range.hpp b/include/samurai/subset/range_traversers/box_traverser_range.hpp new file mode 100644 index 000000000..a7b5817fe --- /dev/null +++ b/include/samurai/subset/range_traversers/box_traverser_range.hpp @@ -0,0 +1,110 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../../interval.hpp" +#include "../traversers/box_traverser.hpp" +#include "set_traverser_range_base.hpp" + +namespace samurai +{ + template + class Box; + + template + class BoxTraverserRange; + + template + struct SetTraverserRangeTraits> + { + static_assert(std::same_as, B>); + + class Iterator + { + public: + + using index_t = typename interval_t::value_t; + + using iterator_category = std::forward_iterator_tag; + using difference_type = index_t; + using value_type = BoxTraverser; + using reference = BoxTraverser; + + Iterator(const interval_t& interval, const index_t& index) + : m_interval(interval) + , m_index(first_index) + { + } + + reference operator*() const + { + return reference(interval); + } + + Iterator& operator++() + { + ++m_index; + return *this; + } + + Iterator operator++(int) + { + Iterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const Iterator& a, const Iterator& b) + { + return a.m_index == b.m_index; + }; + + friend bool operator!=(const Iterator& a, const Iterator& b) + { + return a.m_index != b.m_index; + }; + + private: + + interval_t m_interval; + index_t m_index; + }; + }; + + template + class BoxTraverserRange : public SetTraverserRangeBase> + { + using Self = BoxTraverserRange; + + public: + + SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS + + using interval_t = Interval; + using index_t = typename interval_t::value_t; + + BoxTraverserRange(const interval_t& interval, const index_t& first_index, const index_t& last_index) + : m_interval(interval) + , m_first_index(first_index) + , m_last_index(last_index) + { + } + + Iterator begin_impl() + { + return Iterator(m_interval, m_first_index); + } + + Iterator end_impl() + { + return Iterator(m_interval, m_last_index); + } + + private: + + interval_t m_interval; + index_t m_first_index; + index_t m_last_index; + }; +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/lca_traverser_range.hpp b/include/samurai/subset/range_traversers/lca_traverser_range.hpp index b5037b1d3..e1fae88a9 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range.hpp +++ b/include/samurai/subset/range_traversers/lca_traverser_range.hpp @@ -26,17 +26,16 @@ namespace samurai using interval_iterator = typename std::vector::const_iterator; using offset_iterator = typename std::vector::iterator; - template - class _Iterator + class Iterator { public: using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; - using value_type = LCATraverserRangeItem; - using reference = LCATraverserRangeItem; + using value_type = LCATraverserRangeItem; + using reference = LCATraverserRangeItem; - _Iterator(const interval_iterator first_interval, const offset_iterator offset) + Iterator(const interval_iterator first_interval, const offset_iterator offset) : m_first_interval(first_interval) , m_offset(offset) { @@ -47,25 +46,25 @@ namespace samurai return reference(m_first_interval, m_offset); } - _Iterator& operator++() + Iterator& operator++() { ++m_offset; return *this; } - _Iterator operator++(int) + Iterator operator++(int) { - _Iterator tmp = *this; + Iterator tmp = *this; ++(*this); return tmp; } - friend bool operator==(const _Iterator& a, const _Iterator& b) + friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_first_interval == b.m_first_interval and a.m_offset == b.m_offset; }; - friend bool operator!=(const _Iterator& a, const _Iterator& b) + friend bool operator!=(const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr or a.m_offset != b.m_offset; }; @@ -75,9 +74,6 @@ namespace samurai interval_iterator m_first_interval; offset_iterator m_offset; }; - - using Iterator = _Iterator; - using const_Iterator = _Iterator; }; template @@ -108,16 +104,6 @@ namespace samurai return Iterator(m_first_interval, std::prev(m_last_offsets)); } - const_Iterator begin_impl() const - { - return const_Iterator(m_first_interval, m_first_offsets); - } - - const_Iterator end_impl() const - { - return const_Iterator(m_first_interval, std::prev(m_last_offsets)); - } - private: interval_iterator m_first_interval; diff --git a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp b/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp index 4dad7b579..99d6d855f 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp +++ b/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp @@ -6,16 +6,27 @@ #include #include +#include "../traversers/set_traverser_base.hpp" + namespace samurai { template class LevelCellArray; - template - class LCATraverserRangeItem : public SetTraverserBase> + template + struct SetTraverserTraits> + { + static_assert(std::same_as, LCA>); + + using interval_t = typename LCA::interval_t; + using current_interval_t = const interval_t&; + }; + + template + class LCATraverserRangeItem : public SetTraverserBase> { - using Self = LCATraverserRangeItem; + using Self = LCATraverserRangeItem; public: @@ -37,7 +48,6 @@ namespace samurai } inline void next_interval_impl() - requires(!isConst) { ++m_offset; } diff --git a/include/samurai/subset/range_traversers/nary_traverser_range.hpp b/include/samurai/subset/range_traversers/nary_traverser_range.hpp new file mode 100644 index 000000000..e5345f7e7 --- /dev/null +++ b/include/samurai/subset/range_traversers/nary_traverser_range.hpp @@ -0,0 +1,120 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "nary_traverser_type.hpp" + +namespace samurai +{ + template + class NaryOperatorTraverserRange; + + template + struct SetTraverserRangeTraits> + { + static_assert((IsSetTraverserRange::value and ...)); + + class Iterator + { + public: + + using ChildrenIterators = std::tuple; + + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = typename NAryTraverserType::Type; + using reference = value_type; + + static constexpr std::size_t nIntervals = std::tuple_size::value; + + Iterator(const ChildrenIterators& innerIterators) + : m_childrenIterators(innerIterators) + { + } + + reference operator*() const + { + return std::apply( + [](const auto&... childrenIterators) -> void + { + return reference((*childrenIterators)...); + }, + m_childrenIterators); + } + + Iterator& operator++() + { + static_for<0, nIntervals>::apply( + [this](const auto i) -> void + { + ++std::get(m_childrenIterators); + }); + return *this; + } + + Iterator operator++(int) + { + Iterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const Iterator& a, const Iterator& b) + { + return a.m_childrenIterators == b.m_childrenIterators; + }; + + friend bool operator!=(const Iterator& a, const Iterator& b) + { + return a.m_childrenIterators != b.m_childrenIterators; + }; + + private: + + ChildrenIterators m_childrenIterators; + }; + }; + + template + class NaryOperatorTraverserRange : public SetTraverserRangeBase> + { + using Self = TranslationTraverserRange; + + public: + + SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS + + using Childrens = std::tuple; + + TranslationTraverserRange(const SetTraverserRanges&... set_traverser_ranges) + : m_set_traverser_ranges(set_traverser_ranges...) + { + } + + Iterator begin_impl() + { + return std::apply( + [](auto&... innerIterators) -> Iterator + { + return Iterator(std::make_tuple(innerIterators.begin()...)); + }, + m_set_traverser_ranges); + } + + Iterator end_impl() + { + return std::apply( + [](auto&... innerIterators) -> Iterator + { + return Iterator(std::make_tuple(innerIterators.end()...)); + }, + m_set_traverser_ranges); + } + + private: + + Childrens m_set_traverser_ranges; + }; + +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/nary_traverser_type.hpp b/include/samurai/subset/range_traversers/nary_traverser_type.hpp new file mode 100644 index 000000000..33ba899c0 --- /dev/null +++ b/include/samurai/subset/range_traversers/nary_traverser_type.hpp @@ -0,0 +1,48 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "../difference_id_traverser.hpp" +#include "../difference_traverser.hpp" +#include "../intersection_traverser.hpp" +#include "../union_traverser.hpp" + +namespace samurai +{ + enum class NAryTraverserType + { + UNION, + INTERSECTION, + DIFFERENCE, + DIFFERENCE_ID + }; + + template + struct NAryTraverserTypeTraits; + + template + struct NAryTraverserTypeTraits + { + using Type = UnionTraverser; + }; + + template + struct NAryTraverserTypeTraits + { + using Type = IntersectionTraverser; + }; + + template + struct NAryTraverserTypeTraits + { + using Type = DifferenceTraverser; + }; + + template + struct NAryTraverserTypeTraits + { + using Type = DifferenceIdTraverser; + }; + +} // namespace samurai diff --git a/include/samurai/subset/range_traversers/set_traverser_range_base.hpp b/include/samurai/subset/range_traversers/set_traverser_range_base.hpp index 415060cde..c741e0f3a 100644 --- a/include/samurai/subset/range_traversers/set_traverser_range_base.hpp +++ b/include/samurai/subset/range_traversers/set_traverser_range_base.hpp @@ -11,6 +11,10 @@ namespace samurai template struct SetTraverserRangeTraits; + /* + * For the sake of conscision, the ranges are only forward range + * but they could easily be converted to a random_access range. + */ template class SetTraverserRangeBase { @@ -18,8 +22,7 @@ namespace samurai using DerivedTraits = SetTraverserRangeTraits; - using Iterator = typename DerivedTraits::Iterator; - using const_Iterator = typename DerivedTraits::const_Iterator; + using Iterator = typename DerivedTraits::Iterator; const Derived& derived_cast() const { @@ -36,14 +39,9 @@ namespace samurai derived_cast().begin_impl(); } - const_Iterator begin() const + Iterator end() { - derived_cast().begin_impl(); - } - - const_Iterator cbegin() const - { - derived_cast().begin_impl(); + derived_cast().end_impl(); } }; @@ -52,9 +50,8 @@ namespace samurai { }; -#define SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS \ - using Base = SetTraverserBase; \ - using Iterator = typename Base::Iterator; \ - using const_Iterator = typename Base::const_Iterator; +#define SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS \ + using Base = SetTraverserBase; \ + using Iterator = typename Base::Iterator; } // namespace samurai diff --git a/include/samurai/subset/range_traversers/translation_traverser_range.hpp b/include/samurai/subset/range_traversers/translation_traverser_range.hpp index 5f9e4409d..b41f0a5b4 100644 --- a/include/samurai/subset/range_traversers/translation_traverser_range.hpp +++ b/include/samurai/subset/range_traversers/translation_traverser_range.hpp @@ -17,22 +17,21 @@ namespace samurai static_assert(IsSetTraverserRange::value); using ChildIterator = typename SetTraverserRange::Iterator; - using const_ChildIterator = typename SetTraverserRange::const_Iterator; + using const_ChildIterator = typename SetTraverserRange::constIterator; using Translation = typename ChildIterator::value_type::value_type; - template - class _Iterator + class Iterator { public: using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; - using value_type = TranslationTraverser; + using value_type = TranslationTraverser; using reference = value_type; - _Iterator(const Inner_Iterator inner_Iterator, const Translation& translation) - : m_innerIterator(inner_Iterator) + Iterator(const InnerIterator innerIterator, const Translation& translation) + : m_innerIterator(innerIterator) , m_translation(translation) { } @@ -42,37 +41,34 @@ namespace samurai return reference(*m_innerIterator, m_translation); } - _Iterator& operator++() + Iterator& operator++() { ++m_innerIterator; return *this; } - _Iterator operator++(int) + Iterator operator++(int) { - _Iterator tmp = *this; + Iterator tmp = *this; ++(*this); return tmp; } - friend bool operator==(const _Iterator& a, const _Iterator& b) + friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_innerIterator == b.m_innerIterator; }; - friend bool operator!=(const _Iterator& a, const _Iterator& b) + friend bool operator!=(const Iterator& a, const Iterator& b) { return a.m_innerIterator != b.m_innerIterator; }; private: - Inner_Iterator m_innerIterator; + ChildIterator m_innerIterator; Translation m_translation; }; - - using Iterator = _Iterator; - using const_Iterator = _Iterator; }; template @@ -102,16 +98,6 @@ namespace samurai return Iterator(m_set_traverser_range.end(), m_translation); } - const_Iterator begin_impl() const - { - return const_Iterator(m_set_traverser_range.cbegin(), m_translation); - } - - const_Iterator end_impl() const - { - return const_Iterator(m_set_traverser_range.cend(), m_translation); - } - private: SetTraverserRange m_set_traverser_range; diff --git a/include/samurai/subset/range_traversers/union_traverser_range.hpp b/include/samurai/subset/range_traversers/union_traverser_range.hpp deleted file mode 100644 index 89a787c15..000000000 --- a/include/samurai/subset/range_traversers/union_traverser_range.hpp +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -namespace samurai -{ - - template - class UnionTraverserRange; - - template - struct SetTraverserRangeTraits> - { - static_assert((IsSetTraverserRange::value and ...)); - - template - class _Iterator - { - public: - - using Childrens = std::tuple; - - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = UnionTraverser; - using reference = value_type; - - static constexpr std::size_t nIntervals = std::tuple_size::value; - - _Iterator(const Inner_Iterators... inner_Iterators) - : m_inner_Iterator(inner_Iterators...) - { - } - - reference operator*() const - { - return std::apply( - [](const auto&... innerIterators) -> void - { - return reference((*innerIterators)...); - }, - m_innerIterators); - } - - _Iterator& operator++() - { - static_for<0, nIntervals>::apply( - [this](const auto i) -> void - { - ++std::get(m_innerIterators); - }); - return *this; - } - - _Iterator operator++(int) - { - _Iterator tmp = *this; - ++(*this); - return tmp; - } - - friend bool operator==(const _Iterator& a, const _Iterator& b) - { - return a.m_inner_Iterator == b.m_inner_Iterator; - }; - - friend bool operator!=(const _Iterator& a, const _Iterator& b) - { - return a.m_inner_Iterator != b.m_inner_Iterator; - }; - - private: - - Childrens m_innerIterators; - }; - - using Iterator = _Iterator; - using const_Iterator = _Iterator; - }; - - template - class UnionTraverserRange : public SetTraverserRangeBase> - { - using Self = TranslationTraverserRange; - - public: - - SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS - - using Childrens = std::tuple; - - TranslationTraverserRange(const SetTraverserRanges&... set_traverser_ranges) - : m_set_traverser_ranges(set_traverser_ranges...) - { - } - - Iterator begin_impl() - { - return std::apply( - [](auto&... innerIterators) -> Iterator - { - return Iterator(innerIterators.begin()...); - }, - m_set_traverser_ranges); - } - - Iterator end_impl() - { - return std::apply( - [](auto&... innerIterators) -> Iterator - { - return Iterator(innerIterators.end()...); - }, - m_set_traverser_ranges); - } - - const_Iterator begin_impl() const - { - return std::apply( - [](const auto&... innerIterators) -> const_Iterator - { - return const_Iterator(innerIterators.cbegin()...); - }, - m_set_traverser_ranges); - } - - const_Iterator end_impl() const - { - return std::apply( - [](const auto&... innerIterators) -> const_Iterator - { - return const_Iterator(innerIterators.cend()...); - }, - m_set_traverser_ranges); - } - - private: - - Childrens m_set_traverser_ranges; - }; - -} // namespace samurai diff --git a/include/samurai/subset/traversers/box_traverser.hpp b/include/samurai/subset/traversers/box_traverser.hpp index e07369c1f..f74e2c4aa 100644 --- a/include/samurai/subset/traversers/box_traverser.hpp +++ b/include/samurai/subset/traversers/box_traverser.hpp @@ -3,13 +3,15 @@ #pragma once -#include "../../box.hpp" #include "../../interval.hpp" #include "set_traverser_base.hpp" #include namespace samurai { + template + class Box; + template class BoxTraverser; diff --git a/include/samurai/subset/traversers/lca_traverser.hpp b/include/samurai/subset/traversers/lca_traverser.hpp index acf33a962..00a1f3620 100644 --- a/include/samurai/subset/traversers/lca_traverser.hpp +++ b/include/samurai/subset/traversers/lca_traverser.hpp @@ -4,7 +4,6 @@ #pragma once #include "set_traverser_base.hpp" -#include namespace samurai { From f673e7997f9bffbdc0a0a1b611182b8be450dcd0 Mon Sep 17 00:00:00 2001 From: Hoffmann Date: Mon, 13 Oct 2025 16:31:32 +0200 Subject: [PATCH 19/28] started to add ranges --- include/samurai/subset/expansion.hpp | 2 +- include/samurai/subset/lca_view.hpp | 166 ++++++++++++++++-- include/samurai/subset/nary_set_operator.hpp | 1 - include/samurai/subset/projection.hpp | 2 +- include/samurai/subset/projection_loi.hpp | 2 +- include/samurai/subset/set_base.hpp | 34 +++- .../box_traverser_range.hpp | 0 .../lca_traverser_range.hpp | 12 +- .../lca_traverser_range_item.hpp | 9 +- .../nary_traverser_range.hpp | 0 .../nary_traverser_type.hpp | 0 .../set_traverser_range_base.hpp | 0 .../translation_traverser_range.hpp | 0 .../traversers/difference_traverser.hpp | 2 +- .../traversers/intersection_traverser.hpp | 2 +- .../traversers/projection_traverser.hpp | 2 + .../subset/traversers/union_traverser.hpp | 2 +- 17 files changed, 193 insertions(+), 43 deletions(-) rename include/samurai/subset/{range_traversers => traverser_ranges}/box_traverser_range.hpp (100%) rename include/samurai/subset/{range_traversers => traverser_ranges}/lca_traverser_range.hpp (88%) rename include/samurai/subset/{range_traversers => traverser_ranges}/lca_traverser_range_item.hpp (87%) rename include/samurai/subset/{range_traversers => traverser_ranges}/nary_traverser_range.hpp (100%) rename include/samurai/subset/{range_traversers => traverser_ranges}/nary_traverser_type.hpp (100%) rename include/samurai/subset/{range_traversers => traverser_ranges}/set_traverser_range_base.hpp (100%) rename include/samurai/subset/{range_traversers => traverser_ranges}/translation_traverser_range.hpp (100%) diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index d873036b4..28e5f30db 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -54,7 +54,7 @@ namespace samurai class Expansion : public SetBase> { using Self = Expansion; - using ChildTraverserArray = detail::ExpansionWork>::Type; + using ChildTraverserArray = typename detail::ExpansionWork>::Type; public: diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index cf82b3de5..0b6db9364 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -4,6 +4,7 @@ #pragma once #include "set_base.hpp" +#include "traverser_ranges/lca_traverser_range.hpp" #include "traversers/lca_traverser.hpp" namespace samurai @@ -20,6 +21,9 @@ namespace samurai template using traverser_t = LCATraverser; + template + using traverser_range_t = LCATraverserRange; + static constexpr std::size_t dim() { return LCA::dim; @@ -42,6 +46,16 @@ namespace samurai { } + LCAView(const LCAView& other) + : m_lca(other.m_lca) + { + } + + LCAView(LCAView&& other) + : m_lca(std::move(other.m_lca)) + { + } + inline std::size_t level_impl() const { return m_lca.level(); @@ -77,18 +91,77 @@ namespace samurai std::integral_constant{}); } + template + inline traverser_range_t + get_traverser_range_impl(const index_min_t& index_min, const index_max_t& index_max, std::integral_constant d_ic) const + requires(d != Base::dim - 1) + { + return get_traverser_range_impl_detail(index_min, + index_max, + m_lca[Base::dim - 1].cbegin(), + m_lca[Base::dim - 1].cend(), + d_ic, + std::integral_constant{}); + } + private: - template - inline traverser_t get_traverser_impl_detail(const index_t& index, - const_interval_iterator begin_y_interval, - const_interval_iterator end_y_interval, - std::integral_constant d_ic, - std::integral_constant dCur_ic) const + template + inline traverser_range_t get_traverser_range_impl_rec_final(const index_min_t& index_min, + const index_max_t& index_max, + const_interval_iterator begin_y_interval, + const_interval_iterator end_y_interval, + std::integral_constant) const { + auto& offsetArray = m_work_offsetArray[d]; + const auto begin_offsetArray = offsetArray.begin(); + + assert(d != Base::dim - 1); + + const auto& ymin = index_min[d]; + const auto& ymax = index_max[d]; + const auto& y_offsets = m_lca.offsets(d + 1); + + const auto lb_y_interval_it = lower_bound_interval(begin_y_interval, end_y_interval, ymin); + const auto up_y_interval_it = std::prev(upper_bound_interval(lb_y_interval_it, end_y_interval, ymax)); + + if (lb_y_interval_it != end_y_interval and lb_y_interval_it <= up_y_interval_it) + { + const std::size_t ymin_offset_idx = lb_y_interval_it->contains(ymin) + ? std::size_t(ymin + lb_y_interval_it->index) + : std::size_t(lb_y_interval_it->start + lb_y_interval_it->index); + const std::size_t ymax_offset_idx = up_y_interval_it->contains(ymax) + ? std::size_t(ymax + up_y_interval_it->index) + : std::size_t(up_y_interval_it->end + up_y_interval_it->index); + for (std::size_t offset_idx = ymin_offset_idx; offset_idx != ymax_offset_idx + 1; ++offset_idx) + { + offsetArray.push_back(y_offsets[offset_idx]); + } + + return traverser_range_t(m_lca[d].cbegin(), begin_offsetArray, offsetArray.end()); + } + else + { + return traverser_range_t(m_lca[d].cbegin(), begin_offsetArray, begin_offsetArray); + } + } + + template + inline traverser_range_t get_traverser_range_impl_rec(const index_min_t& index_min, + const index_max_t& index_max, + const_interval_iterator begin_y_interval, + const_interval_iterator end_y_interval, + std::integral_constant d_ic, + std::integral_constant) const + { + if constexpr (d == dCur) + { + return get_traverser_range_impl_rec_final(index_min, index_max, begin_y_interval, end_y_interval, d_ic); + } if constexpr (dCur != Base::dim - 1) { - const auto& y = index[dCur]; + assert(index_min[dCur] == index_max[dCur]); + const auto& y = index_min[dCur]; const auto& y_offsets = m_lca.offsets(dCur + 1); // we need to find an interval that contains y. const auto y_interval_it = std::find_if(begin_y_interval, @@ -104,37 +177,94 @@ namespace samurai const_interval_iterator begin_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]); const_interval_iterator end_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1]); - return get_traverser_impl_detail_wrapper(index, begin_x_interval, end_x_interval, d_ic, dCur_ic); + return get_traverser_range_impl_rec(index_min, + index_max, + begin_x_interval, + end_x_interval, + d_ic, + std::integral_constant{}); } else { - return get_traverser_impl_detail_wrapper(index, m_lca[dCur].cend(), m_lca[dCur].cend(), d_ic, dCur_ic); + return get_traverser_range_impl_rec(index_min, + index_max, + m_lca[dCur].cend(), + m_lca[dCur].cend(), + d_ic, + std::integral_constant{}); } } else { - return get_traverser_impl_detail_wrapper(index, m_lca[dCur].cbegin(), m_lca[dCur].cend(), d_ic, dCur_ic); + return get_traverser_range_impl_rec(index_min, + index_max, + m_lca[dCur].cbegin(), + m_lca[dCur].cend(), + d_ic, + std::integral_constant{}); } } template - inline traverser_t get_traverser_impl_detail_wrapper(const index_t& index, - const_interval_iterator begin_x_interval, - const_interval_iterator end_x_interval, - std::integral_constant d_ic, - std::integral_constant) const + inline traverser_t get_traverser_impl_detail(const index_t& index, + const_interval_iterator begin_y_interval, + const_interval_iterator end_y_interval, + std::integral_constant d_ic, + std::integral_constant) const { - if constexpr (d == dCur) + if constexpr (dCur != Base::dim - 1) + { + const auto& y = index[dCur]; + const auto& y_offsets = m_lca.offsets(dCur + 1); + // we need to find an interval that contains y. + const auto y_interval_it = std::find_if(begin_y_interval, + end_y_interval, + [y](const auto& y_interval) + { + return y_interval.contains(y); + }); + if (y_interval_it != end_y_interval) + { + const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); + + const_interval_iterator begin_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]); + const_interval_iterator end_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1]); + + if constexpr (d == dCur) + { + return traverser_t(begin_x_interval, end_x_interval); + } + else + { + return get_traverser_impl_detail(index, + begin_x_interval, + end_x_interval, + d_ic, + std::integral_constant{}); + } + } + else + { + return traverser_t(m_lca[d].cend(), m_lca[d].cend()); + } + } + else if constexpr (d != dCur) { - return traverser_t(begin_x_interval, end_x_interval); + return get_traverser_impl_detail(index, + m_lca[dCur].cbegin(), + m_lca[dCur].cend(), + d_ic, + std::integral_constant{}); } else { - return get_traverser_impl_detail(index, begin_x_interval, end_x_interval, d_ic, std::integral_constant{}); + return traverser_t(m_lca[dCur].cbegin(), m_lca[dCur].cend()); } } const LCA& m_lca; + + mutable std::array, Base::dim> m_work_offsetArray; }; template diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 2df60d937..7107411a6 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -3,7 +3,6 @@ #pragma once -#include "nary_set_operator_types.hpp" #include "set_base.hpp" #include "traversers/difference_id_traverser.hpp" #include "traversers/difference_traverser.hpp" diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index d651e25e2..6f8d055ef 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -50,7 +50,7 @@ namespace samurai class Projection : public SetBase> { using Self = Projection; - using ChildTraverserArray = detail::ProjectionWork>::Type; + using ChildTraverserArray = typename detail::ProjectionWork>::Type; public: diff --git a/include/samurai/subset/projection_loi.hpp b/include/samurai/subset/projection_loi.hpp index 2e13c6676..5d730e4cd 100644 --- a/include/samurai/subset/projection_loi.hpp +++ b/include/samurai/subset/projection_loi.hpp @@ -58,7 +58,7 @@ namespace samurai class ProjectionLOI : public SetBase> { using Self = ProjectionLOI; - using ListOfIntervals = detail::ProjectionLOIWork>::Type; + using ListOfIntervals = typename detail::ProjectionLOIWork>::Type; public: diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 1f0aff9ca..770cea4aa 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -8,6 +8,7 @@ #include #include "../samurai_config.hpp" +#include "traverser_ranges/set_traverser_range_base.hpp" #include "traversers/set_traverser_base.hpp" namespace samurai @@ -44,8 +45,12 @@ namespace samurai template using traverser_t = typename DerivedTraits::template traverser_t; - using interval_t = typename traverser_t<0>::interval_t; - using value_t = typename interval_t::value_t; + + template + using traverser_range_t = typename DerivedTraits::template traverser_range_t; + + using interval_t = typename traverser_t<0>::interval_t; + using value_t = typename interval_t::value_t; using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; @@ -97,6 +102,14 @@ namespace samurai return derived_cast().get_traverser_impl(index, d_ic); } + template + inline traverser_range_t + get_traverser_range(const index_min_t& index_min, const index_max_t& index_max, std::integral_constant d_ic) const + requires(d != dim - 1) + { + return derived_cast().get_traverser_range_impl(index_min, index_max, d_ic); + } + inline ProjectionMethod on(const std::size_t level); template @@ -168,13 +181,16 @@ namespace samurai } }; -#define SAMURAI_SET_TYPEDEFS \ - using Base = SetBase; \ - \ - template \ - using traverser_t = typename Base::template traverser_t; \ - \ - using interval_t = typename Base::interval_t; \ +#define SAMURAI_SET_TYPEDEFS \ + using Base = SetBase; \ + \ + template \ + using traverser_t = typename Base::template traverser_t; \ + \ + template \ + using traverser_range_t = typename Base::template traverser_range_t; \ + \ + using interval_t = typename Base::interval_t; \ using value_t = typename Base::value_t; template diff --git a/include/samurai/subset/range_traversers/box_traverser_range.hpp b/include/samurai/subset/traverser_ranges/box_traverser_range.hpp similarity index 100% rename from include/samurai/subset/range_traversers/box_traverser_range.hpp rename to include/samurai/subset/traverser_ranges/box_traverser_range.hpp diff --git a/include/samurai/subset/range_traversers/lca_traverser_range.hpp b/include/samurai/subset/traverser_ranges/lca_traverser_range.hpp similarity index 88% rename from include/samurai/subset/range_traversers/lca_traverser_range.hpp rename to include/samurai/subset/traverser_ranges/lca_traverser_range.hpp index e1fae88a9..b7871ecc6 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range.hpp +++ b/include/samurai/subset/traverser_ranges/lca_traverser_range.hpp @@ -23,7 +23,7 @@ namespace samurai { static_assert(std::same_as, LCA>); - using interval_iterator = typename std::vector::const_iterator; + using interval_iterator = typename std::vector::const_iterator; using offset_iterator = typename std::vector::iterator; class Iterator @@ -62,12 +62,12 @@ namespace samurai friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_first_interval == b.m_first_interval and a.m_offset == b.m_offset; - }; + } friend bool operator!=(const Iterator& a, const Iterator& b) { - return a.m_ptr != b.m_ptr or a.m_offset != b.m_offset; - }; + return a.m_first_interval != b.m_first_interval or a.m_offset != b.m_offset; + } private: @@ -84,7 +84,7 @@ namespace samurai public: SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS - using interval_iterator = typename std::vector::const_iterator; + using interval_iterator = typename std::vector::const_iterator; using offset_iterator = typename std::vector::iterator; LCATraverserRange(const interval_iterator first_interval, const offset_iterator first_offsets, const offset_iterator last_offsets) @@ -101,7 +101,7 @@ namespace samurai Iterator end_impl() { - return Iterator(m_first_interval, std::prev(m_last_offsets)); + return Iterator(m_first_interval, m_last_offsets); } private: diff --git a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp b/include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp similarity index 87% rename from include/samurai/subset/range_traversers/lca_traverser_range_item.hpp rename to include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp index 99d6d855f..f050d3070 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range_item.hpp +++ b/include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp @@ -14,6 +14,9 @@ namespace samurai template class LevelCellArray; + template + class LCATraverserRangeItem; + template struct SetTraverserTraits> { @@ -33,7 +36,7 @@ namespace samurai SAMURAI_SET_TRAVERSER_TYPEDEFS using interval_iterator = typename std::vector::const_iterator; - using offset_iterator = typename std::vector::iterator; + using offset_iterator = typename std::vector::iterator; LCATraverserRangeItem(const interval_iterator first_interval, const offset_iterator offset) : m_first_interval(first_interval) @@ -60,8 +63,8 @@ namespace samurai private: interval_iterator m_first_interval; - std::size_t& m_offset; - std::size_t m_offset_bound; + std::ptrdiff_t& m_offset; + std::ptrdiff_t m_offset_bound; }; } // namespace samurai diff --git a/include/samurai/subset/range_traversers/nary_traverser_range.hpp b/include/samurai/subset/traverser_ranges/nary_traverser_range.hpp similarity index 100% rename from include/samurai/subset/range_traversers/nary_traverser_range.hpp rename to include/samurai/subset/traverser_ranges/nary_traverser_range.hpp diff --git a/include/samurai/subset/range_traversers/nary_traverser_type.hpp b/include/samurai/subset/traverser_ranges/nary_traverser_type.hpp similarity index 100% rename from include/samurai/subset/range_traversers/nary_traverser_type.hpp rename to include/samurai/subset/traverser_ranges/nary_traverser_type.hpp diff --git a/include/samurai/subset/range_traversers/set_traverser_range_base.hpp b/include/samurai/subset/traverser_ranges/set_traverser_range_base.hpp similarity index 100% rename from include/samurai/subset/range_traversers/set_traverser_range_base.hpp rename to include/samurai/subset/traverser_ranges/set_traverser_range_base.hpp diff --git a/include/samurai/subset/range_traversers/translation_traverser_range.hpp b/include/samurai/subset/traverser_ranges/translation_traverser_range.hpp similarity index 100% rename from include/samurai/subset/range_traversers/translation_traverser_range.hpp rename to include/samurai/subset/traverser_ranges/translation_traverser_range.hpp diff --git a/include/samurai/subset/traversers/difference_traverser.hpp b/include/samurai/subset/traversers/difference_traverser.hpp index 6f3c7bdd3..50d279d30 100644 --- a/include/samurai/subset/traversers/difference_traverser.hpp +++ b/include/samurai/subset/traversers/difference_traverser.hpp @@ -33,7 +33,7 @@ namespace samurai using Childrens = std::tuple; template - using IthChild = std::tuple_element::type; + using IthChild = typename std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; diff --git a/include/samurai/subset/traversers/intersection_traverser.hpp b/include/samurai/subset/traversers/intersection_traverser.hpp index 54c9a3089..86050bc23 100644 --- a/include/samurai/subset/traversers/intersection_traverser.hpp +++ b/include/samurai/subset/traversers/intersection_traverser.hpp @@ -32,7 +32,7 @@ namespace samurai using Childrens = std::tuple; template - using IthChild = std::tuple_element::type; + using IthChild = typename std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size_v; diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 267e0df1e..407bf735f 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -3,6 +3,8 @@ #pragma once +#include + #include "../projection_type.hpp" #include "set_traverser_base.hpp" diff --git a/include/samurai/subset/traversers/union_traverser.hpp b/include/samurai/subset/traversers/union_traverser.hpp index 00dc22b81..2b8d4fb98 100644 --- a/include/samurai/subset/traversers/union_traverser.hpp +++ b/include/samurai/subset/traversers/union_traverser.hpp @@ -32,7 +32,7 @@ namespace samurai using Childrens = std::tuple; template - using IthChild = std::tuple_element::type; + using IthChild = typename std::tuple_element::type; static constexpr std::size_t nIntervals = std::tuple_size::value; From 75b71b712ed7967b49bebed23689839065701155 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Tue, 14 Oct 2025 12:04:36 +0200 Subject: [PATCH 20/28] range partly implemented 2 --- include/samurai/subset/range_traversers/lca_traverser_range.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/samurai/subset/range_traversers/lca_traverser_range.hpp b/include/samurai/subset/range_traversers/lca_traverser_range.hpp index e1fae88a9..8b5f84ac8 100644 --- a/include/samurai/subset/range_traversers/lca_traverser_range.hpp +++ b/include/samurai/subset/range_traversers/lca_traverser_range.hpp @@ -66,7 +66,7 @@ namespace samurai friend bool operator!=(const Iterator& a, const Iterator& b) { - return a.m_ptr != b.m_ptr or a.m_offset != b.m_offset; + return a.m_first_interval != b.m_first_interval or a.m_offset != b.m_offset; }; private: From f9af70688982e3f6e5dd3a461e54b6ba54eea05e Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Tue, 14 Oct 2025 17:45:31 +0200 Subject: [PATCH 21/28] changed mutable attribute to an external workspace --- include/samurai/subset/apply.hpp | 19 ++- include/samurai/subset/box_view.hpp | 13 +- include/samurai/subset/contraction.hpp | 20 +-- include/samurai/subset/expansion.hpp | 98 ++++++------- include/samurai/subset/lca_view.hpp | 129 +----------------- include/samurai/subset/nary_set_operator.hpp | 46 ++++--- include/samurai/subset/projection.hpp | 88 +++++------- include/samurai/subset/projection_loi.hpp | 115 ++++++++-------- include/samurai/subset/set_base.hpp | 68 ++++----- include/samurai/subset/translation.hpp | 21 +-- .../traverser_ranges/box_traverser_range.hpp | 110 --------------- .../traverser_ranges/lca_traverser_range.hpp | 114 ---------------- .../lca_traverser_range_item.hpp | 70 ---------- .../traverser_ranges/nary_traverser_range.hpp | 120 ---------------- .../traverser_ranges/nary_traverser_type.hpp | 48 ------- .../set_traverser_range_base.hpp | 57 -------- .../translation_traverser_range.hpp | 107 --------------- .../traversers/projection_loi_traverser.hpp | 2 +- .../traversers/projection_traverser.hpp | 25 ++-- .../subset/traversers/set_traverser_base.hpp | 8 +- tests/test_subset.cpp | 4 - 21 files changed, 250 insertions(+), 1032 deletions(-) delete mode 100644 include/samurai/subset/traverser_ranges/box_traverser_range.hpp delete mode 100644 include/samurai/subset/traverser_ranges/lca_traverser_range.hpp delete mode 100644 include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp delete mode 100644 include/samurai/subset/traverser_ranges/nary_traverser_range.hpp delete mode 100644 include/samurai/subset/traverser_ranges/nary_traverser_type.hpp delete mode 100644 include/samurai/subset/traverser_ranges/set_traverser_range_base.hpp delete mode 100644 include/samurai/subset/traverser_ranges/translation_traverser_range.hpp diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index c75ebfb62..d502acc7f 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -10,14 +10,18 @@ namespace samurai namespace detail { template - void apply_rec(const SetBase& set, Func&& func, Index& index, std::integral_constant d_ic) + void apply_rec(const SetBase& set, + Func&& func, + Index& index, + std::integral_constant d_ic, + typename SetBase::Workspace& workspace) { using traverser_t = typename Set::template traverser_t; using current_interval_t = typename traverser_t::current_interval_t; - set.init_get_traverser_work(1, d_ic); + set.init_workspace(1, d_ic, workspace); - for (traverser_t traverser = set.get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) + for (traverser_t traverser = set.get_traverser(index, d_ic, workspace); !traverser.is_empty(); traverser.next_interval()) { current_interval_t interval = traverser.current_interval(); @@ -29,24 +33,25 @@ namespace samurai { for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) { - apply_rec(set, std::forward(func), index, std::integral_constant{}); + apply_rec(set, std::forward(func), index, std::integral_constant{}, workspace); } } } - - set.clear_get_traverser_work(d_ic); } } template void apply(const SetBase& set, Func&& func) { + using Workspace = typename SetBase::Workspace; + constexpr std::size_t dim = Set::dim; xt::xtensor_fixed> index; if (set.exist()) { - detail::apply_rec(set, std::forward(func), index, std::integral_constant{}); + Workspace workspace; + detail::apply_rec(set, std::forward(func), index, std::integral_constant{}, workspace); } } } diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index b2b6153b3..33818713c 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -20,6 +20,10 @@ namespace samurai template using traverser_t = BoxTraverser; + struct Workspace + { + }; + static constexpr std::size_t dim() { return B::dim; @@ -57,7 +61,7 @@ namespace samurai } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant, Workspace) const { return (m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]) ? traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]) @@ -65,12 +69,7 @@ namespace samurai } template - constexpr inline void init_get_traverser_work_impl(const std::size_t, std::integral_constant) const - { - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant) const + inline constexpr void init_workspace_impl(const std::size_t, std::integral_constant, Workspace) const { } diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 784e66144..bc240beca 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -20,6 +20,11 @@ namespace samurai template using traverser_t = ContractionTraverser>; + struct Workspace + { + typename Set::Workspace child_workspace; + }; + static constexpr std::size_t dim() { return Set::dim; @@ -82,21 +87,16 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const - { - m_set.init_get_traverser_work(n_traversers, d_ic); - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + inline void + init_workspace_impl(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { - m_set.clear_get_traverser_work(d_ic); + m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const { - return traverser_t(m_set.get_traverser(index, d_ic), m_contraction[d]); + return traverser_t(m_set.get_traverser(index, d_ic, workspace.child_workspace), m_contraction[d]); } private: diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 28e5f30db..c0825ae3b 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -10,32 +10,13 @@ namespace samurai { - template - class Expansion; - - template - struct SetTraits> - { - static_assert(IsSet::value); - - template - using traverser_t = std::conditional_t>, - ExpansionTraverser>>; - - static constexpr std::size_t dim() - { - return Set::dim; - } - }; - namespace detail { template - struct ExpansionWork; + struct ExpansionWorkspace; template - struct ExpansionWork> + struct ExpansionWorkspace> { template using child_traverser_t = typename Set::template traverser_t; @@ -50,11 +31,35 @@ namespace samurai } // namespace detail + template + class Expansion; + + template + struct SetTraits> + { + static_assert(IsSet::value); + + template + using traverser_t = std::conditional_t>, + ExpansionTraverser>>; + + struct Workspace + { + typename detail::ExpansionWorkspace>::Type expansion_workspace; + typename Set::Workspace child_workspace; + }; + + static constexpr std::size_t dim() + { + return Set::dim; + } + }; + template class Expansion : public SetBase> { - using Self = Expansion; - using ChildTraverserArray = typename detail::ExpansionWork>::Type; + using Self = Expansion; public: @@ -84,20 +89,6 @@ namespace samurai } } - // we need to define a custom copy and move constructor because - // we do not want to copy m_work_offsetRanges - Expansion(const Expansion& other) - : m_set(other.m_set) - , m_expansions(other.m_expansions) - { - } - - Expansion(Expansion&& other) - : m_set(other.m_set) - , m_expansions(other.m_expansions) - { - } - inline std::size_t level_impl() const { return m_set.level(); @@ -114,46 +105,35 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + inline void + init_workspace_impl(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { if constexpr (d == Base::dim - 1) { - m_set.init_get_traverser_work_impl(n_traversers, d_ic); + m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } else { const std::size_t my_work_size = n_traversers * 2 * std::size_t(m_expansions[d + 1] + 1); - auto& childTraversers = std::get(m_work_childTraversers); + auto& childTraversers = std::get(workspace.expansion_workspace); childTraversers.clear(); childTraversers.reserve(my_work_size); - m_set.init_get_traverser_work_impl(my_work_size, d_ic); - } - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const - { - if constexpr (d != Base::dim - 1) - { - auto& childTraversers = std::get(m_work_childTraversers); - - childTraversers.clear(); + m_set.init_workspace(my_work_size, d_ic, workspace.child_workspace); } - m_set.clear_get_traverser_work(d_ic); } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const { if constexpr (d == Base::dim - 1) { - return traverser_t(m_set.get_traverser(index, d_ic), m_expansions[d]); + return traverser_t(m_set.get_traverser(index, d_ic, workspace.child_workspace), m_expansions[d]); } else { - auto& childTraversers = std::get(m_work_childTraversers); + auto& childTraversers = std::get(workspace.expansion_workspace); xt::xtensor_fixed> tmp_index(index); @@ -162,14 +142,14 @@ namespace samurai for (value_t width = 0; width != m_expansions[d + 1] + 1; ++width) { tmp_index[d + 1] = index[d + 1] + width; - childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic)); + childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { childTraversers.pop_back(); } tmp_index[d + 1] = index[d + 1] - width; - childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic)); + childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { childTraversers.pop_back(); @@ -184,8 +164,6 @@ namespace samurai Set m_set; expansion_t m_expansions; - - mutable ChildTraverserArray m_work_childTraversers; }; template diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 0b6db9364..35f7a5353 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -4,7 +4,6 @@ #pragma once #include "set_base.hpp" -#include "traverser_ranges/lca_traverser_range.hpp" #include "traversers/lca_traverser.hpp" namespace samurai @@ -21,8 +20,9 @@ namespace samurai template using traverser_t = LCATraverser; - template - using traverser_range_t = LCATraverserRange; + struct Workspace + { + }; static constexpr std::size_t dim() { @@ -72,17 +72,12 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t, std::integral_constant) const - { - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant) const + inline constexpr void init_workspace_impl(const std::size_t, std::integral_constant, Workspace) const { } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace) const { return get_traverser_impl_detail(index, m_lca[Base::dim - 1].cbegin(), @@ -91,120 +86,8 @@ namespace samurai std::integral_constant{}); } - template - inline traverser_range_t - get_traverser_range_impl(const index_min_t& index_min, const index_max_t& index_max, std::integral_constant d_ic) const - requires(d != Base::dim - 1) - { - return get_traverser_range_impl_detail(index_min, - index_max, - m_lca[Base::dim - 1].cbegin(), - m_lca[Base::dim - 1].cend(), - d_ic, - std::integral_constant{}); - } - private: - template - inline traverser_range_t get_traverser_range_impl_rec_final(const index_min_t& index_min, - const index_max_t& index_max, - const_interval_iterator begin_y_interval, - const_interval_iterator end_y_interval, - std::integral_constant) const - { - auto& offsetArray = m_work_offsetArray[d]; - const auto begin_offsetArray = offsetArray.begin(); - - assert(d != Base::dim - 1); - - const auto& ymin = index_min[d]; - const auto& ymax = index_max[d]; - const auto& y_offsets = m_lca.offsets(d + 1); - - const auto lb_y_interval_it = lower_bound_interval(begin_y_interval, end_y_interval, ymin); - const auto up_y_interval_it = std::prev(upper_bound_interval(lb_y_interval_it, end_y_interval, ymax)); - - if (lb_y_interval_it != end_y_interval and lb_y_interval_it <= up_y_interval_it) - { - const std::size_t ymin_offset_idx = lb_y_interval_it->contains(ymin) - ? std::size_t(ymin + lb_y_interval_it->index) - : std::size_t(lb_y_interval_it->start + lb_y_interval_it->index); - const std::size_t ymax_offset_idx = up_y_interval_it->contains(ymax) - ? std::size_t(ymax + up_y_interval_it->index) - : std::size_t(up_y_interval_it->end + up_y_interval_it->index); - for (std::size_t offset_idx = ymin_offset_idx; offset_idx != ymax_offset_idx + 1; ++offset_idx) - { - offsetArray.push_back(y_offsets[offset_idx]); - } - - return traverser_range_t(m_lca[d].cbegin(), begin_offsetArray, offsetArray.end()); - } - else - { - return traverser_range_t(m_lca[d].cbegin(), begin_offsetArray, begin_offsetArray); - } - } - - template - inline traverser_range_t get_traverser_range_impl_rec(const index_min_t& index_min, - const index_max_t& index_max, - const_interval_iterator begin_y_interval, - const_interval_iterator end_y_interval, - std::integral_constant d_ic, - std::integral_constant) const - { - if constexpr (d == dCur) - { - return get_traverser_range_impl_rec_final(index_min, index_max, begin_y_interval, end_y_interval, d_ic); - } - if constexpr (dCur != Base::dim - 1) - { - assert(index_min[dCur] == index_max[dCur]); - const auto& y = index_min[dCur]; - const auto& y_offsets = m_lca.offsets(dCur + 1); - // we need to find an interval that contains y. - const auto y_interval_it = std::find_if(begin_y_interval, - end_y_interval, - [y](const auto& y_interval) - { - return y_interval.contains(y); - }); - if (y_interval_it != end_y_interval) - { - const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); - - const_interval_iterator begin_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]); - const_interval_iterator end_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1]); - - return get_traverser_range_impl_rec(index_min, - index_max, - begin_x_interval, - end_x_interval, - d_ic, - std::integral_constant{}); - } - else - { - return get_traverser_range_impl_rec(index_min, - index_max, - m_lca[dCur].cend(), - m_lca[dCur].cend(), - d_ic, - std::integral_constant{}); - } - } - else - { - return get_traverser_range_impl_rec(index_min, - index_max, - m_lca[dCur].cbegin(), - m_lca[dCur].cend(), - d_ic, - std::integral_constant{}); - } - } - template inline traverser_t get_traverser_impl_detail(const index_t& index, const_interval_iterator begin_y_interval, @@ -263,8 +146,6 @@ namespace samurai } const LCA& m_lca; - - mutable std::array, Base::dim> m_work_offsetArray; }; template diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 7107411a6..811879dc8 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -30,6 +30,11 @@ namespace samurai template using traverser_t = UnionTraverser...>; + struct Workspace + { + std::tuple children_workspaces; + }; + static constexpr std::size_t dim() { return std::tuple_element_t<0, std::tuple>::dim; @@ -44,6 +49,11 @@ namespace samurai template using traverser_t = IntersectionTraverser...>; + struct Workspace + { + std::tuple children_workspaces; + }; + static constexpr std::size_t dim() { return std::tuple_element_t<0, std::tuple>::dim; @@ -60,6 +70,11 @@ namespace samurai DifferenceTraverser...>, DifferenceIdTraverser...>>; + struct Workspace + { + std::tuple children_workspaces; + }; + static constexpr std::size_t dim() { return std::tuple_element_t<0, std::tuple>::dim; @@ -128,38 +143,33 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const - { - static_for<0, nIntervals>::apply( - [this, n_traversers, d_ic](const auto i) -> void - { - std::get(m_sets).init_get_traverser_work(n_traversers, d_ic); - }); - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + inline void + init_workspace_impl(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { static_for<0, nIntervals>::apply( - [this, d_ic](const auto i) -> void + [this, n_traversers, d_ic, &workspace](const auto i) -> void { - std::get(m_sets).clear_get_traverser_work(d_ic); + std::get(m_sets).init_workspace(n_traversers, d_ic, std::get(workspace.children_workspaces)); }); } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const { - return get_traverser_impl_detail(index, d_ic, std::make_index_sequence{}); + return get_traverser_impl_detail(index, d_ic, std::make_index_sequence{}, workspace); } private: template - traverser_t - get_traverser_impl_detail(const index_t& index, std::integral_constant d_ic, std::index_sequence) const + traverser_t get_traverser_impl_detail(const index_t& index, + std::integral_constant d_ic, + std::index_sequence, + Workspace& workspace) const { - return traverser_t(m_shifts, std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic)...); + return traverser_t( + m_shifts, + std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic, std::get(workspace.children_workspaces))...); } Childrens m_sets; diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 6f8d055ef..a4014290e 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -11,23 +11,6 @@ namespace samurai { - template - class Projection; - - template - struct SetTraits> - { - static_assert(IsSet::value); - - template - using traverser_t = ProjectionTraverser>; - - static constexpr std::size_t dim() - { - return Set::dim; - } - }; - namespace detail { template @@ -46,6 +29,29 @@ namespace samurai }; } // namespace detail + template + class Projection; + + template + struct SetTraits> + { + static_assert(IsSet::value); + + template + using traverser_t = ProjectionTraverser>; + + struct Workspace + { + typename detail::ProjectionWork>::Type projection_workspace; + typename Set::Workspace child_workspace; + }; + + static constexpr std::size_t dim() + { + return Set::dim; + } + }; + template class Projection : public SetBase> { @@ -72,24 +78,6 @@ namespace samurai } } - // we need to define a custom copy and move constructor because - // we do not want to copy m_work_offsetRanges - Projection(const Projection& other) - : m_set(other.m_set) - , m_level(other.m_level) - , m_projectionType(other.m_projectionType) - , m_shift(other.m_shift) - { - } - - Projection(Projection&& other) - : m_set(std::move(other.m_set)) - , m_level(std::move(other.m_level)) - , m_projectionType(std::move(other.m_projectionType)) - , m_shift(std::move(other.m_shift)) - { - } - inline std::size_t level_impl() const { return m_level; @@ -106,34 +94,26 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + inline void + init_workspace_impl(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { const std::size_t my_work_size_per_traverser = (m_projectionType == ProjectionType::COARSEN and d != Base::dim - 1) ? (1 << m_shift) : 1; const std::size_t my_work_size = n_traversers * my_work_size_per_traverser; - auto& childTraversers = std::get(m_work_childTraversers); + auto& childTraversers = std::get(workspace.projection_workspace); childTraversers.clear(); childTraversers.reserve(my_work_size); - m_set.init_get_traverser_work(my_work_size, d_ic); - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const - { - auto& childTraversers = std::get(m_work_childTraversers); - - childTraversers.clear(); - - m_set.clear_get_traverser_work(d_ic); + m_set.init_workspace(my_work_size, d_ic, workspace.child_workspace); } template - inline traverser_t get_traverser_impl(const index_t& _index, std::integral_constant d_ic) const + inline traverser_t + get_traverser_impl(const index_t& _index, std::integral_constant d_ic, Workspace& workspace) const { - auto& childTraversers = std::get(m_work_childTraversers); + auto& childTraversers = std::get(workspace.projection_workspace); if (m_projectionType == ProjectionType::COARSEN) { @@ -150,7 +130,7 @@ namespace samurai for (index[d] = ymin; index[d] != ybound; ++index[d]) { - childTraversers.push_back(m_set.get_traverser(index, d_ic)); + childTraversers.push_back(m_set.get_traverser(index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { childTraversers.pop_back(); @@ -163,13 +143,13 @@ namespace samurai } else { - childTraversers.push_back(m_set.get_traverser(_index << m_shift, d_ic)); + childTraversers.push_back(m_set.get_traverser(_index << m_shift, d_ic, workspace.child_workspace)); return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } else { - childTraversers.push_back(m_set.get_traverser(_index >> m_shift, d_ic)); + childTraversers.push_back(m_set.get_traverser(_index >> m_shift, d_ic, workspace.child_workspace)); return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } @@ -180,8 +160,6 @@ namespace samurai std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; - - mutable ChildTraverserArray m_work_childTraversers; }; } // namespace samurai diff --git a/include/samurai/subset/projection_loi.hpp b/include/samurai/subset/projection_loi.hpp index 5d730e4cd..8099d950c 100644 --- a/include/samurai/subset/projection_loi.hpp +++ b/include/samurai/subset/projection_loi.hpp @@ -14,6 +14,24 @@ namespace samurai { + namespace detail + { + template + struct ProjectionLOIWork; + + template + struct ProjectionLOIWork> + { + template + using child_traverser_t = typename Set::template traverser_t; + + template + using work_t = ListOfIntervals::value_t>; + + using Type = std::tuple...>; + }; + } // namespace detail + template class ProjectionLOI; @@ -30,30 +48,18 @@ namespace samurai LastDimProjectionLOITraverser>, ProjectionLOITraverser>>; + struct Workspace + { + typename detail::ProjectionLOIWork>::Type projection_workspace; + typename Set::Workspace child_workspace; + }; + static constexpr std::size_t dim() { return Set::dim; } }; - namespace detail - { - template - struct ProjectionLOIWork; - - template - struct ProjectionLOIWork> - { - template - using child_traverser_t = typename Set::template traverser_t; - - template - using work_t = ListOfIntervals::value_t>; - - using Type = std::tuple...>; - }; - } // namespace detail - template class ProjectionLOI : public SetBase> { @@ -64,7 +70,8 @@ namespace samurai SAMURAI_SET_TYPEDEFS - using Index = xt::xtensor_fixed>; + using Index = xt::xtensor_fixed>; + using ChildWorkspace = typename Set::Workspace; ProjectionLOI(const Set& set, const std::size_t level) : m_set(set) @@ -82,24 +89,6 @@ namespace samurai } } - // we need to define a custom copy and move constructor because - // we do not want to copy m_work_offsetRanges - ProjectionLOI(const ProjectionLOI& other) - : m_set(other.m_set) - , m_level(other.m_level) - , m_projectionType(other.m_projectionType) - , m_shift(other.m_shift) - { - } - - ProjectionLOI(ProjectionLOI&& other) - : m_set(std::move(other.m_set)) - , m_level(std::move(other.m_level)) - , m_projectionType(std::move(other.m_projectionType)) - , m_shift(std::move(other.m_shift)) - { - } - inline std::size_t level_impl() const { return m_level; @@ -116,23 +105,18 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const + inline void + init_workspace_impl(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { assert(n_traversers == 1); - m_set.init_get_traverser_work(n_traversers, d_ic); - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const - { - m_set.clear_get_traverser_work(d_ic); + m_set.init_get_traverser_work(n_traversers, d_ic, workspace.child_workspace); } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const { - auto& listOfIntervals = std::get(m_work_listOfIntervals); + auto& listOfIntervals = std::get(workspace.projection_workspace); listOfIntervals.clear(); if (m_projectionType == ProjectionType::COARSEN) @@ -143,18 +127,27 @@ namespace samurai Index index_max((index + 1) << m_shift); Index index_rec; - fill_list_of_interval_rec(index_min, index_max, index_rec, d_ic, std::integral_constant{}); - - return traverser_t(m_set.get_traverser(index << m_shift, d_ic), listOfIntervals.cbegin(), listOfIntervals.cend()); + ChildWorkspace child_workspace; + fill_list_of_interval_rec(index_min, + index_max, + index_rec, + d_ic, + std::integral_constant{}, + child_workspace, + workspace); + + return traverser_t(m_set.get_traverser(index << m_shift, d_ic, workspace.child_workspace), + listOfIntervals.cbegin(), + listOfIntervals.cend()); } else { - return traverser_t(m_set.get_traverser(index << m_shift, d_ic), m_projectionType, m_shift); + return traverser_t(m_set.get_traverser(index << m_shift, d_ic, workspace.child_workspace), m_projectionType, m_shift); } } else { - return traverser_t(m_set.get_traverser(index >> m_shift, d_ic), m_projectionType, m_shift); + return traverser_t(m_set.get_traverser(index >> m_shift, d_ic, workspace.child_workspace), m_projectionType, m_shift); } } @@ -165,18 +158,22 @@ namespace samurai const Index& index_max, index_t& index, std::integral_constant d_ic, - std::integral_constant dCur_ic) const + std::integral_constant dCur_ic, + ChildWorkspace& child_workspace, + Workspace& workspace_to_fill) const { using child_traverser_t = typename Set::template traverser_t; using child_current_interval_t = typename child_traverser_t::current_interval_t; + m_set.init_workspace(1, dCur_ic, child_workspace); + for (child_traverser_t traverser = m_set.get_traverser(index, dCur_ic); !traverser.is_empty(); traverser.next_interval()) { child_current_interval_t interval = traverser.current_interval(); if constexpr (dCur == d) { - std::get(m_work_listOfIntervals).add_interval(interval >> m_shift); + std::get(workspace_to_fill.projection_workspace).add_interval(interval >> m_shift); } else { @@ -185,7 +182,13 @@ namespace samurai for (index[dCur - 1] = index_start; index[dCur - 1] < index_end; ++index[dCur - 1]) { - fill_list_of_interval_rec(index_min, index_max, index, d_ic, std::integral_constant{}); + fill_list_of_interval_rec(index_min, + index_max, + index, + d_ic, + std::integral_constant{}, + child_workspace, + workspace_to_fill); } } } @@ -195,8 +198,6 @@ namespace samurai std::size_t m_level; ProjectionType m_projectionType; std::size_t m_shift; - - mutable ListOfIntervals m_work_listOfIntervals; }; } // namespace samurai diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 770cea4aa..32d953c0f 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -8,7 +8,6 @@ #include #include "../samurai_config.hpp" -#include "traverser_ranges/set_traverser_range_base.hpp" #include "traversers/set_traverser_base.hpp" namespace samurai @@ -17,7 +16,14 @@ namespace samurai //// Forward Declarations //////////////////////////////////////////////////////////////////////// - template + /** + * Traits used by `SetBase` + * it must define: + * 1. a template type traverser_t + * 2. a Workspace class + * 3. a constexpr dim() method + */ + template struct SetTraits; template @@ -45,9 +51,7 @@ namespace samurai template using traverser_t = typename DerivedTraits::template traverser_t; - - template - using traverser_range_t = typename DerivedTraits::template traverser_range_t; + using Workspace = typename DerivedTraits::Workspace; using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; @@ -85,29 +89,15 @@ namespace samurai } template - inline void init_get_traverser_work(const std::size_t n_traversers, std::integral_constant d_ic) const + inline void init_workspace(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { - derived_cast().init_get_traverser_work_impl(n_traversers, d_ic); - } - - template - inline void clear_get_traverser_work(std::integral_constant d_ic) const - { - derived_cast().clear_get_traverser_work_impl(d_ic); + derived_cast().init_workspace_impl(n_traversers, d_ic, workspace); } template - inline traverser_t get_traverser(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const { - return derived_cast().get_traverser_impl(index, d_ic); - } - - template - inline traverser_range_t - get_traverser_range(const index_min_t& index_min, const index_max_t& index_max, std::integral_constant d_ic) const - requires(d != dim - 1) - { - return derived_cast().get_traverser_range_impl(index_min, index_max, d_ic); + return derived_cast().get_traverser_impl(index, d_ic, workspace); } inline ProjectionMethod on(const std::size_t level); @@ -145,17 +135,18 @@ namespace samurai inline bool empty_default_impl() const { xt::xtensor_fixed> index; - return empty_default_impl_rec(index, std::integral_constant{}); + Workspace workspace; + return empty_default_impl_rec(index, std::integral_constant{}, workspace); } template - bool empty_default_impl_rec(index_t& index, std::integral_constant d_ic) const + bool empty_default_impl_rec(index_t& index, std::integral_constant d_ic, Workspace& workspace) const { using current_interval_t = typename traverser_t::current_interval_t; - init_get_traverser_work(1, d_ic); + init_workspace(1, d_ic, workspace); - for (traverser_t traverser = get_traverser(index, d_ic); !traverser.is_empty(); traverser.next_interval()) + for (traverser_t traverser = get_traverser(index, d_ic, workspace); !traverser.is_empty(); traverser.next_interval()) { current_interval_t interval = traverser.current_interval(); @@ -167,7 +158,7 @@ namespace samurai { for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) { - if (not empty_default_impl_rec(index, std::integral_constant{})) + if (not empty_default_impl_rec(index, std::integral_constant{}, workspace)) { return false; } @@ -175,22 +166,19 @@ namespace samurai } } - clear_get_traverser_work(d_ic); - return true; } }; -#define SAMURAI_SET_TYPEDEFS \ - using Base = SetBase; \ - \ - template \ - using traverser_t = typename Base::template traverser_t; \ - \ - template \ - using traverser_range_t = typename Base::template traverser_range_t; \ - \ - using interval_t = typename Base::interval_t; \ +#define SAMURAI_SET_TYPEDEFS \ + using Base = SetBase; \ + \ + template \ + using traverser_t = typename Base::template traverser_t; \ + \ + using Workspace = typename Base::Workspace; \ + \ + using interval_t = typename Base::interval_t; \ using value_t = typename Base::value_t; template diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 208774513..4930c3f2e 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -23,6 +23,11 @@ namespace samurai template using traverser_t = TranslationTraverser>; + struct Workspace + { + typename Set::Workspace child_workspace; + }; + static constexpr std::size_t dim() { return Set::dim; @@ -63,21 +68,17 @@ namespace samurai } template - inline void init_get_traverser_work_impl(const std::size_t n_traversers, std::integral_constant d_ic) const - { - m_set.init_get_traverser_work(n_traversers, d_ic); - } - - template - inline void clear_get_traverser_work_impl(std::integral_constant d_ic) const + inline void + init_workspace_impl(const std::size_t n_traversers, std::integral_constant d_ic, Workspace& workspace) const { - m_set.clear_get_traverser_work(d_ic); + m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const { - return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic), m_translation[d]); + return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic, workspace.child_workspace), + m_translation[d]); } private: diff --git a/include/samurai/subset/traverser_ranges/box_traverser_range.hpp b/include/samurai/subset/traverser_ranges/box_traverser_range.hpp deleted file mode 100644 index a7b5817fe..000000000 --- a/include/samurai/subset/traverser_ranges/box_traverser_range.hpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include "../../interval.hpp" -#include "../traversers/box_traverser.hpp" -#include "set_traverser_range_base.hpp" - -namespace samurai -{ - template - class Box; - - template - class BoxTraverserRange; - - template - struct SetTraverserRangeTraits> - { - static_assert(std::same_as, B>); - - class Iterator - { - public: - - using index_t = typename interval_t::value_t; - - using iterator_category = std::forward_iterator_tag; - using difference_type = index_t; - using value_type = BoxTraverser; - using reference = BoxTraverser; - - Iterator(const interval_t& interval, const index_t& index) - : m_interval(interval) - , m_index(first_index) - { - } - - reference operator*() const - { - return reference(interval); - } - - Iterator& operator++() - { - ++m_index; - return *this; - } - - Iterator operator++(int) - { - Iterator tmp = *this; - ++(*this); - return tmp; - } - - friend bool operator==(const Iterator& a, const Iterator& b) - { - return a.m_index == b.m_index; - }; - - friend bool operator!=(const Iterator& a, const Iterator& b) - { - return a.m_index != b.m_index; - }; - - private: - - interval_t m_interval; - index_t m_index; - }; - }; - - template - class BoxTraverserRange : public SetTraverserRangeBase> - { - using Self = BoxTraverserRange; - - public: - - SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS - - using interval_t = Interval; - using index_t = typename interval_t::value_t; - - BoxTraverserRange(const interval_t& interval, const index_t& first_index, const index_t& last_index) - : m_interval(interval) - , m_first_index(first_index) - , m_last_index(last_index) - { - } - - Iterator begin_impl() - { - return Iterator(m_interval, m_first_index); - } - - Iterator end_impl() - { - return Iterator(m_interval, m_last_index); - } - - private: - - interval_t m_interval; - index_t m_first_index; - index_t m_last_index; - }; -} // namespace samurai diff --git a/include/samurai/subset/traverser_ranges/lca_traverser_range.hpp b/include/samurai/subset/traverser_ranges/lca_traverser_range.hpp deleted file mode 100644 index b7871ecc6..000000000 --- a/include/samurai/subset/traverser_ranges/lca_traverser_range.hpp +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include - -#include "lca_traverser_range_item.hpp" -#include "set_traverser_range_base.hpp" - -namespace samurai -{ - - template - class LevelCellArray; - - template - class LCATraverserRange; - - template - struct SetTraverserRangeTraits> - { - static_assert(std::same_as, LCA>); - - using interval_iterator = typename std::vector::const_iterator; - using offset_iterator = typename std::vector::iterator; - - class Iterator - { - public: - - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = LCATraverserRangeItem; - using reference = LCATraverserRangeItem; - - Iterator(const interval_iterator first_interval, const offset_iterator offset) - : m_first_interval(first_interval) - , m_offset(offset) - { - } - - reference operator*() const - { - return reference(m_first_interval, m_offset); - } - - Iterator& operator++() - { - ++m_offset; - return *this; - } - - Iterator operator++(int) - { - Iterator tmp = *this; - ++(*this); - return tmp; - } - - friend bool operator==(const Iterator& a, const Iterator& b) - { - return a.m_first_interval == b.m_first_interval and a.m_offset == b.m_offset; - } - - friend bool operator!=(const Iterator& a, const Iterator& b) - { - return a.m_first_interval != b.m_first_interval or a.m_offset != b.m_offset; - } - - private: - - interval_iterator m_first_interval; - offset_iterator m_offset; - }; - }; - - template - class LCATraverserRange : public SetTraverserRangeBase> - { - using Self = LCATraverserRange; - - public: - - SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS - using interval_iterator = typename std::vector::const_iterator; - using offset_iterator = typename std::vector::iterator; - - LCATraverserRange(const interval_iterator first_interval, const offset_iterator first_offsets, const offset_iterator last_offsets) - : m_first_interval(first_interval) - , m_first_offsets(first_offsets) - , m_last_offsets(last_offsets) - { - } - - Iterator begin_impl() - { - return Iterator(m_first_interval, m_first_offsets); - } - - Iterator end_impl() - { - return Iterator(m_first_interval, m_last_offsets); - } - - private: - - interval_iterator m_first_interval; - offset_iterator m_first_offsets; - offset_iterator m_last_offsets; - }; - -} // namespace samurai diff --git a/include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp b/include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp deleted file mode 100644 index f050d3070..000000000 --- a/include/samurai/subset/traverser_ranges/lca_traverser_range_item.hpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include - -#include "../traversers/set_traverser_base.hpp" - -namespace samurai -{ - - template - class LevelCellArray; - - template - class LCATraverserRangeItem; - - template - struct SetTraverserTraits> - { - static_assert(std::same_as, LCA>); - - using interval_t = typename LCA::interval_t; - using current_interval_t = const interval_t&; - }; - - template - class LCATraverserRangeItem : public SetTraverserBase> - { - using Self = LCATraverserRangeItem; - - public: - - SAMURAI_SET_TRAVERSER_TYPEDEFS - - using interval_iterator = typename std::vector::const_iterator; - using offset_iterator = typename std::vector::iterator; - - LCATraverserRangeItem(const interval_iterator first_interval, const offset_iterator offset) - : m_first_interval(first_interval) - , m_offset(*offset) - , m_offset_bound(*(offset + 1)) - { - } - - inline bool is_empty_impl() const - { - return m_offset == m_offset_bound; - } - - inline void next_interval_impl() - { - ++m_offset; - } - - inline current_interval_t current_interval_impl() const - { - return *(m_first_interval + m_offset); - } - - private: - - interval_iterator m_first_interval; - std::ptrdiff_t& m_offset; - std::ptrdiff_t m_offset_bound; - }; - -} // namespace samurai diff --git a/include/samurai/subset/traverser_ranges/nary_traverser_range.hpp b/include/samurai/subset/traverser_ranges/nary_traverser_range.hpp deleted file mode 100644 index e5345f7e7..000000000 --- a/include/samurai/subset/traverser_ranges/nary_traverser_range.hpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include "nary_traverser_type.hpp" - -namespace samurai -{ - template - class NaryOperatorTraverserRange; - - template - struct SetTraverserRangeTraits> - { - static_assert((IsSetTraverserRange::value and ...)); - - class Iterator - { - public: - - using ChildrenIterators = std::tuple; - - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = typename NAryTraverserType::Type; - using reference = value_type; - - static constexpr std::size_t nIntervals = std::tuple_size::value; - - Iterator(const ChildrenIterators& innerIterators) - : m_childrenIterators(innerIterators) - { - } - - reference operator*() const - { - return std::apply( - [](const auto&... childrenIterators) -> void - { - return reference((*childrenIterators)...); - }, - m_childrenIterators); - } - - Iterator& operator++() - { - static_for<0, nIntervals>::apply( - [this](const auto i) -> void - { - ++std::get(m_childrenIterators); - }); - return *this; - } - - Iterator operator++(int) - { - Iterator tmp = *this; - ++(*this); - return tmp; - } - - friend bool operator==(const Iterator& a, const Iterator& b) - { - return a.m_childrenIterators == b.m_childrenIterators; - }; - - friend bool operator!=(const Iterator& a, const Iterator& b) - { - return a.m_childrenIterators != b.m_childrenIterators; - }; - - private: - - ChildrenIterators m_childrenIterators; - }; - }; - - template - class NaryOperatorTraverserRange : public SetTraverserRangeBase> - { - using Self = TranslationTraverserRange; - - public: - - SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS - - using Childrens = std::tuple; - - TranslationTraverserRange(const SetTraverserRanges&... set_traverser_ranges) - : m_set_traverser_ranges(set_traverser_ranges...) - { - } - - Iterator begin_impl() - { - return std::apply( - [](auto&... innerIterators) -> Iterator - { - return Iterator(std::make_tuple(innerIterators.begin()...)); - }, - m_set_traverser_ranges); - } - - Iterator end_impl() - { - return std::apply( - [](auto&... innerIterators) -> Iterator - { - return Iterator(std::make_tuple(innerIterators.end()...)); - }, - m_set_traverser_ranges); - } - - private: - - Childrens m_set_traverser_ranges; - }; - -} // namespace samurai diff --git a/include/samurai/subset/traverser_ranges/nary_traverser_type.hpp b/include/samurai/subset/traverser_ranges/nary_traverser_type.hpp deleted file mode 100644 index 33ba899c0..000000000 --- a/include/samurai/subset/traverser_ranges/nary_traverser_type.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include "../difference_id_traverser.hpp" -#include "../difference_traverser.hpp" -#include "../intersection_traverser.hpp" -#include "../union_traverser.hpp" - -namespace samurai -{ - enum class NAryTraverserType - { - UNION, - INTERSECTION, - DIFFERENCE, - DIFFERENCE_ID - }; - - template - struct NAryTraverserTypeTraits; - - template - struct NAryTraverserTypeTraits - { - using Type = UnionTraverser; - }; - - template - struct NAryTraverserTypeTraits - { - using Type = IntersectionTraverser; - }; - - template - struct NAryTraverserTypeTraits - { - using Type = DifferenceTraverser; - }; - - template - struct NAryTraverserTypeTraits - { - using Type = DifferenceIdTraverser; - }; - -} // namespace samurai diff --git a/include/samurai/subset/traverser_ranges/set_traverser_range_base.hpp b/include/samurai/subset/traverser_ranges/set_traverser_range_base.hpp deleted file mode 100644 index c741e0f3a..000000000 --- a/include/samurai/subset/traverser_ranges/set_traverser_range_base.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include -#include - -namespace samurai -{ - template - struct SetTraverserRangeTraits; - - /* - * For the sake of conscision, the ranges are only forward range - * but they could easily be converted to a random_access range. - */ - template - class SetTraverserRangeBase - { - public: - - using DerivedTraits = SetTraverserRangeTraits; - - using Iterator = typename DerivedTraits::Iterator; - - const Derived& derived_cast() const - { - return static_cast(*this); - } - - Derived& derived_cast() - { - return static_cast(*this); - } - - Iterator begin() - { - derived_cast().begin_impl(); - } - - Iterator end() - { - derived_cast().end_impl(); - } - }; - - template - struct IsSetTraverserRange : std::bool_constant, T>::value> - { - }; - -#define SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS \ - using Base = SetTraverserBase; \ - using Iterator = typename Base::Iterator; - -} // namespace samurai diff --git a/include/samurai/subset/traverser_ranges/translation_traverser_range.hpp b/include/samurai/subset/traverser_ranges/translation_traverser_range.hpp deleted file mode 100644 index b41f0a5b4..000000000 --- a/include/samurai/subset/traverser_ranges/translation_traverser_range.hpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2018-2025 the samurai's authors -// SPDX-License-Identifier: BSD-3-Clause - -#pragma once - -#include "set_traverser_range_base.hpp" - -namespace samurai -{ - - template - class TranslationTraverserRange; - - template - struct SetTraverserRangeTraits> - { - static_assert(IsSetTraverserRange::value); - - using ChildIterator = typename SetTraverserRange::Iterator; - using const_ChildIterator = typename SetTraverserRange::constIterator; - - using Translation = typename ChildIterator::value_type::value_type; - - class Iterator - { - public: - - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = TranslationTraverser; - using reference = value_type; - - Iterator(const InnerIterator innerIterator, const Translation& translation) - : m_innerIterator(innerIterator) - , m_translation(translation) - { - } - - reference operator*() const - { - return reference(*m_innerIterator, m_translation); - } - - Iterator& operator++() - { - ++m_innerIterator; - return *this; - } - - Iterator operator++(int) - { - Iterator tmp = *this; - ++(*this); - return tmp; - } - - friend bool operator==(const Iterator& a, const Iterator& b) - { - return a.m_innerIterator == b.m_innerIterator; - }; - - friend bool operator!=(const Iterator& a, const Iterator& b) - { - return a.m_innerIterator != b.m_innerIterator; - }; - - private: - - ChildIterator m_innerIterator; - Translation m_translation; - }; - }; - - template - class TranslationTraverserRange : public SetTraverserRangeBase> - { - using Self = TranslationTraverserRange; - - public: - - SAMURAI_SET_TRAVERSER_RANGE_TYPEDEFS - - using Translation = typename SetTraverserRangeTraits::Translation; - - TranslationTraverserRange(const SetTraverserRange& set_traverser_range, const Translation& translation) - : m_set_traverser_range(set_traverser_range) - , m_translation(translation) - { - } - - Iterator begin_impl() - { - return Iterator(m_set_traverser_range.begin(), m_translation); - } - - Iterator end_impl() - { - return Iterator(m_set_traverser_range.end(), m_translation); - } - - private: - - SetTraverserRange m_set_traverser_range; - Translation m_translation; - }; - -} // namespace samurai diff --git a/include/samurai/subset/traversers/projection_loi_traverser.hpp b/include/samurai/subset/traversers/projection_loi_traverser.hpp index 32afbc79f..0c07b314a 100644 --- a/include/samurai/subset/traversers/projection_loi_traverser.hpp +++ b/include/samurai/subset/traversers/projection_loi_traverser.hpp @@ -30,7 +30,7 @@ namespace samurai SAMURAI_SET_TRAVERSER_TYPEDEFS - ProjectionLOITraverser(SetTraverser set_traverser, const ProjectionType projectionType, const std::size_t shift) + ProjectionLOITraverser(SetTraverser set_traverser, [[maybe_unused]] const ProjectionType projectionType, const std::size_t shift) : m_set_traverser(set_traverser) , m_shift(shift) , m_projectionType(ProjectionType::REFINE) diff --git a/include/samurai/subset/traversers/projection_traverser.hpp b/include/samurai/subset/traversers/projection_traverser.hpp index 407bf735f..7cdcb353a 100644 --- a/include/samurai/subset/traversers/projection_traverser.hpp +++ b/include/samurai/subset/traversers/projection_traverser.hpp @@ -42,23 +42,24 @@ namespace samurai { if (m_projectionType == ProjectionType::COARSEN) { - m_current_interval.start = coarsen_start(m_set_traversers[0].current_interval()); - m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); + m_current_interval.start = coarsen_start(m_set_traversers.front().current_interval()); + m_current_interval.end = coarsen_end(m_set_traversers.front().current_interval()); - m_set_traversers[0].next_interval(); + m_set_traversers.front().next_interval(); // when coarsening, two disjoint intervals may be merged. // we need to check if the next_interval overlaps - for (; !m_set_traversers[0].is_empty() && coarsen_start(m_set_traversers[0].current_interval()) <= m_current_interval.end; - m_set_traversers[0].next_interval()) + for (; !m_set_traversers.front().is_empty() + && coarsen_start(m_set_traversers.front().current_interval()) <= m_current_interval.end; + m_set_traversers.front().next_interval()) { - m_current_interval.end = coarsen_end(m_set_traversers[0].current_interval()); + m_current_interval.end = coarsen_end(m_set_traversers.front().current_interval()); } } else { - m_current_interval.start = m_set_traversers[0].current_interval().start << shift; - m_current_interval.end = m_set_traversers[0].current_interval().end << shift; + m_current_interval.start = m_set_traversers.front().current_interval().start << shift; + m_current_interval.end = m_set_traversers.front().current_interval().end << shift; } } } @@ -87,12 +88,12 @@ namespace samurai } else { - m_set_traversers[0].next_interval(); - m_isEmpty = m_set_traversers[0].is_empty(); + m_set_traversers.front().next_interval(); + m_isEmpty = m_set_traversers.front().is_empty(); if (!m_isEmpty) { - m_current_interval.start = m_set_traversers[0].current_interval().start << m_shift; - m_current_interval.end = m_set_traversers[0].current_interval().end << m_shift; + m_current_interval.start = m_set_traversers.front().current_interval().start << m_shift; + m_current_interval.end = m_set_traversers.front().current_interval().end << m_shift; } } } diff --git a/include/samurai/subset/traversers/set_traverser_base.hpp b/include/samurai/subset/traversers/set_traverser_base.hpp index 2d7855293..6bcd63e96 100644 --- a/include/samurai/subset/traversers/set_traverser_base.hpp +++ b/include/samurai/subset/traversers/set_traverser_base.hpp @@ -8,7 +8,13 @@ namespace samurai { - template + /** + * Traits used by `SetTraverserBase` + * it must define: + * 1. an interval_t class + * 2. a current_interval_t class + */ + template struct SetTraverserTraits; template diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index e1f0c256a..031037ae6 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -1305,10 +1305,6 @@ namespace samurai ca = {cl, true}; - std::cout << self(ca[4]).on(3).to_lca() << std::endl; - - fmt::print("===============================================\n"); - // Test self-similarity at different scales bool found = false; apply(intersection(ca[3], self(ca[4]).on(3)), From 634b88c158872ab74e74c1128154411b9383469f Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 15 Oct 2025 10:54:00 +0200 Subject: [PATCH 22/28] lca_view revisited - finite-volume-advection-3d added --- demos/FiniteVolume/CMakeLists.txt | 1 + demos/FiniteVolume/advection_3d.cpp | 165 ++++++++++++++++++++++ include/samurai/samurai_config.hpp | 2 +- include/samurai/subset/lca_view.hpp | 114 ++++++--------- include/samurai/subset/projection_loi.hpp | 5 +- tests/test_subset.cpp | 1 - 6 files changed, 212 insertions(+), 76 deletions(-) create mode 100644 demos/FiniteVolume/advection_3d.cpp diff --git a/demos/FiniteVolume/CMakeLists.txt b/demos/FiniteVolume/CMakeLists.txt index 8ff4b2bf9..f117398c3 100644 --- a/demos/FiniteVolume/CMakeLists.txt +++ b/demos/FiniteVolume/CMakeLists.txt @@ -17,6 +17,7 @@ level_set.cpp:finite-volume-level-set level_set_from_scratch.cpp:finite-volume-level-set-from-scratch advection_1d.cpp:finite-volume-advection-1d advection_2d.cpp:finite-volume-advection-2d +advection_3d.cpp:finite-volume-advection-3d advection_2d_user_bc.cpp:finite-volume-advection-2d-user-bc scalar_burgers_2d.cpp:finite-volume-scalar-burgers-2d linear_convection_obstacle.cpp:finite-volume-linear-convection-obstacle diff --git a/demos/FiniteVolume/advection_3d.cpp b/demos/FiniteVolume/advection_3d.cpp new file mode 100644 index 000000000..c69731471 --- /dev/null +++ b/demos/FiniteVolume/advection_3d.cpp @@ -0,0 +1,165 @@ +// Copyright 2018-2025 the samurai's authors +// SPDX-License-Identifier: BSD-3-Clause + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +namespace fs = std::filesystem; + +template +void init(Field& u) +{ + auto& mesh = u.mesh(); + u.resize(); + + samurai::for_each_cell(mesh, + [&](auto& cell) + { + auto center = cell.center(); + const double radius = .2; + const double x_center = 0.3; + const double y_center = 0.3; + const double z_center = 0.3; + if (((center[0] - x_center) * (center[0] - x_center) + (center[1] - y_center) * (center[1] - y_center) + + (center[2] - z_center) * (center[2] - z_center)) + <= radius * radius) + { + u[cell] = 1; + } + else + { + u[cell] = 0; + } + }); +} + +template +void save(const fs::path& path, const std::string& filename, const Field& u, const std::string& suffix = "") +{ + auto& mesh = u.mesh(); + +#ifdef SAMURAI_WITH_MPI + mpi::communicator world; + samurai::save(path, fmt::format("{}_size_{}{}", filename, world.size(), suffix), mesh, u); +#else + samurai::save(path, fmt::format("{}{}", filename, suffix), mesh, u); + samurai::dump(path, fmt::format("{}_restart{}", filename, suffix), mesh, u); +#endif +} + +int main(int argc, char* argv[]) +{ + auto& app = samurai::initialize("Finite volume example for the advection equation in 3d using multiresolution", argc, argv); + + constexpr std::size_t dim = 3; + using Config = samurai::MRConfig; + + // Simulation parameters + xt::xtensor_fixed> min_corner = {0., 0., 0.}; + xt::xtensor_fixed> max_corner = {1., 1., 1.}; + std::array a{ + {1, 1, 1} + }; + double Tf = .1; + double cfl = 0.25; + double t = 0.; + std::string restart_file; + + // Multiresolution parameters + std::size_t min_level = 4; + std::size_t max_level = 10; + + // Output parameters + fs::path path = fs::current_path(); + std::string filename = "FV_advection_3d"; + std::size_t nfiles = 1; + + app.add_option("--min-corner", min_corner, "The min corner of the box")->capture_default_str()->group("Simulation parameters"); + app.add_option("--max-corner", max_corner, "The max corner of the box")->capture_default_str()->group("Simulation parameters"); + app.add_option("--velocity", a, "The velocity of the advection equation")->capture_default_str()->group("Simulation parameters"); + app.add_option("--cfl", cfl, "The CFL")->capture_default_str()->group("Simulation parameters"); + app.add_option("--Ti", t, "Initial time")->capture_default_str()->group("Simulation parameters"); + app.add_option("--Tf", Tf, "Final time")->capture_default_str()->group("Simulation parameters"); + app.add_option("--restart-file", restart_file, "Restart file")->capture_default_str()->group("Simulation parameters"); + app.add_option("--min-level", min_level, "Minimum level of the multiresolution")->capture_default_str()->group("Multiresolution"); + app.add_option("--max-level", max_level, "Maximum level of the multiresolution")->capture_default_str()->group("Multiresolution"); + app.add_option("--path", path, "Output path")->capture_default_str()->group("Output"); + app.add_option("--filename", filename, "File name prefix")->capture_default_str()->group("Output"); + app.add_option("--nfiles", nfiles, "Number of output files")->capture_default_str()->group("Output"); + + SAMURAI_PARSE(argc, argv); + + const samurai::Box box(min_corner, max_corner); + samurai::MRMesh mesh; + auto u = samurai::make_scalar_field("u", mesh); + + if (restart_file.empty()) + { + mesh = { + box, + min_level, + max_level, + {true, true, true} + }; + init(u); + } + else + { + samurai::load(restart_file, mesh, u); + } + // samurai::make_bc>(u, 0.); + + double dt = cfl * mesh.cell_length(max_level); + const double dt_save = Tf / static_cast(nfiles); + + auto unp1 = samurai::make_scalar_field("unp1", mesh); + + auto MRadaptation = samurai::make_MRAdapt(u); + auto mra_config = samurai::mra_config().epsilon(2e-4); + MRadaptation(mra_config); + save(path, filename, u, "_init"); + + std::size_t nsave = 1; + std::size_t nt = 0; + + while (t != Tf) + { + MRadaptation(mra_config); + + t += dt; + if (t > Tf) + { + dt += Tf - t; + t = Tf; + } + + std::cout << fmt::format("iteration {}: t = {}, dt = {}", nt++, t, dt) << std::endl; + + samurai::update_ghost_mr(u); + unp1.resize(); + unp1 = u - dt * samurai::upwind(a, u); + + std::swap(u.array(), unp1.array()); + + if (t >= static_cast(nsave + 1) * dt_save || t == Tf) + { + const std::string suffix = (nfiles != 1) ? fmt::format("_ite_{}", nsave++) : ""; + save(path, filename, u, suffix); + } + } + samurai::finalize(); + return 0; +} diff --git a/include/samurai/samurai_config.hpp b/include/samurai/samurai_config.hpp index f5ac59a5a..ba0ebd361 100644 --- a/include/samurai/samurai_config.hpp +++ b/include/samurai/samurai_config.hpp @@ -20,7 +20,7 @@ namespace samurai static constexpr std::size_t graduation_width = 1; static constexpr std::size_t prediction_order = 1; - static constexpr bool prediction_with_list_of_intervals = false; + static constexpr bool prediction_with_list_of_intervals = true; using index_t = signed long long int; using value_t = int; diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 35f7a5353..77cb5ea43 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -22,6 +22,11 @@ namespace samurai struct Workspace { + // we do not need the offsets for the last dim + // the offset at dimension d will be initialized when calling + // get_traverser_impl + std::array start_offset; + std::array end_offset; }; static constexpr std::size_t dim() @@ -39,23 +44,11 @@ namespace samurai SAMURAI_SET_TYPEDEFS - using const_interval_iterator = typename std::vector::const_iterator; - explicit LCAView(const LCA& lca) : m_lca(lca) { } - LCAView(const LCAView& other) - : m_lca(other.m_lca) - { - } - - LCAView(LCAView&& other) - : m_lca(std::move(other.m_lca)) - { - } - inline std::size_t level_impl() const { return m_lca.level(); @@ -72,79 +65,56 @@ namespace samurai } template - inline constexpr void init_workspace_impl(const std::size_t, std::integral_constant, Workspace) const + inline constexpr void init_workspace_impl(const std::size_t, std::integral_constant, Workspace&) const { } template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace) const + inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant, Workspace& workspace) const { - return get_traverser_impl_detail(index, - m_lca[Base::dim - 1].cbegin(), - m_lca[Base::dim - 1].cend(), - d_ic, - std::integral_constant{}); - } - - private: - - template - inline traverser_t get_traverser_impl_detail(const index_t& index, - const_interval_iterator begin_y_interval, - const_interval_iterator end_y_interval, - std::integral_constant d_ic, - std::integral_constant) const - { - if constexpr (dCur != Base::dim - 1) + if constexpr (d == Base::dim - 1) + { + return traverser_t(m_lca[d].cbegin(), m_lca[d].cend()); + } + else { - const auto& y = index[dCur]; - const auto& y_offsets = m_lca.offsets(dCur + 1); - // we need to find an interval that contains y. - const auto y_interval_it = std::find_if(begin_y_interval, - end_y_interval, - [y](const auto& y_interval) + // In 3d, we would be in the y dimension + // we need to find an interval that contains the prescibed z. + const auto& z_intervals = m_lca[d + 1]; + const auto begin_z_interval = (d == Base::dim - 2) ? z_intervals.cbegin() + : z_intervals.cbegin() + workspace.start_offset[d + 1]; + const auto end_z_interval = (d == Base::dim - 2) ? z_intervals.cend() : z_intervals.cbegin() + workspace.end_offset[d + 1]; + + const auto z = index[d]; + + const auto z_interval_it = std::find_if(begin_z_interval, + end_z_interval, + [z](const auto& z_interval) { - return y_interval.contains(y); + return z_interval.contains(z); }); - if (y_interval_it != end_y_interval) - { - const std::size_t y_offset_idx = std::size_t(y + y_interval_it->index); - - const_interval_iterator begin_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx]); - const_interval_iterator end_x_interval = m_lca[dCur].cbegin() + ptrdiff_t(y_offsets[y_offset_idx + 1]); - - if constexpr (d == dCur) - { - return traverser_t(begin_x_interval, end_x_interval); - } - else - { - return get_traverser_impl_detail(index, - begin_x_interval, - end_x_interval, - d_ic, - std::integral_constant{}); - } - } - else + + const auto& y_intervals = m_lca[d]; + + auto& y_start_offset = workspace.start_offset[d]; + auto& y_end_offset = workspace.end_offset[d]; + + if (z_interval_it == end_z_interval) { - return traverser_t(m_lca[d].cend(), m_lca[d].cend()); + y_start_offset = y_end_offset; + return traverser_t(y_intervals.cend(), y_intervals.cend()); } - } - else if constexpr (d != dCur) - { - return get_traverser_impl_detail(index, - m_lca[dCur].cbegin(), - m_lca[dCur].cend(), - d_ic, - std::integral_constant{}); - } - else - { - return traverser_t(m_lca[dCur].cbegin(), m_lca[dCur].cend()); + const auto& y_offsets = m_lca.offsets(d + 1); + const auto y_offset_idx = std::size_t(z_interval_it->index + z); + + y_start_offset = std::ptrdiff_t(y_offsets[y_offset_idx]); + y_end_offset = std::ptrdiff_t(y_offsets[y_offset_idx + 1]); + return traverser_t(y_intervals.cbegin() + y_start_offset, y_intervals.cbegin() + y_end_offset); } } + private: + const LCA& m_lca; }; diff --git a/include/samurai/subset/projection_loi.hpp b/include/samurai/subset/projection_loi.hpp index 8099d950c..3dd14fd4a 100644 --- a/include/samurai/subset/projection_loi.hpp +++ b/include/samurai/subset/projection_loi.hpp @@ -110,7 +110,7 @@ namespace samurai { assert(n_traversers == 1); - m_set.init_get_traverser_work(n_traversers, d_ic, workspace.child_workspace); + m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } template @@ -167,7 +167,8 @@ namespace samurai m_set.init_workspace(1, dCur_ic, child_workspace); - for (child_traverser_t traverser = m_set.get_traverser(index, dCur_ic); !traverser.is_empty(); traverser.next_interval()) + for (child_traverser_t traverser = m_set.get_traverser(index, dCur_ic, child_workspace); !traverser.is_empty(); + traverser.next_interval()) { child_current_interval_t interval = traverser.current_interval(); diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 031037ae6..3171b246c 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -458,7 +458,6 @@ namespace samurai {5, {5, 33}} }; std::size_t ie = 0; - fmt::print("====================================================\n"); apply(union_(ca_1[7], ca_2[7]).on(6), [&](auto& i, auto& index) { From 65890802921e13891891d6a7dd2b83092bfd6f60 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 15 Oct 2025 11:11:43 +0200 Subject: [PATCH 23/28] dumb stuff in projection_loi --- include/samurai/subset/traversers/projection_loi_traverser.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/samurai/subset/traversers/projection_loi_traverser.hpp b/include/samurai/subset/traversers/projection_loi_traverser.hpp index 0c07b314a..7244cad31 100644 --- a/include/samurai/subset/traversers/projection_loi_traverser.hpp +++ b/include/samurai/subset/traversers/projection_loi_traverser.hpp @@ -40,6 +40,7 @@ namespace samurai ProjectionLOITraverser(SetTraverser set_traverser, SetTraverserIterator first_interval, SetTraverserIterator bound_interval) : m_set_traverser(set_traverser) + , m_shift(0) , m_first_interval(first_interval) , m_bound_interval(bound_interval) , m_projectionType(ProjectionType::COARSEN) From e9693b10bdafe2adbee9372b914788caa4e087f8 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 15 Oct 2025 11:26:56 +0200 Subject: [PATCH 24/28] dumb stuff in expansion traverser --- include/samurai/subset/traversers/expansion_traverser.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/samurai/subset/traversers/expansion_traverser.hpp b/include/samurai/subset/traversers/expansion_traverser.hpp index 947369935..a88769d50 100644 --- a/include/samurai/subset/traversers/expansion_traverser.hpp +++ b/include/samurai/subset/traversers/expansion_traverser.hpp @@ -94,7 +94,6 @@ namespace samurai std::span m_set_traversers; value_t m_expansion; interval_t m_current_interval; - bool m_isEmpty; }; } // namespace samurai From ee5198bd1248262bdb76efc1072c36e302a99cc0 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 15 Oct 2025 14:29:07 +0200 Subject: [PATCH 25/28] removed xfunctions and xviews --- include/samurai/subset/apply.hpp | 19 ++--- include/samurai/subset/box_view.hpp | 4 +- include/samurai/subset/contraction.hpp | 5 +- include/samurai/subset/expansion.hpp | 14 ++-- include/samurai/subset/lca_view.hpp | 4 +- include/samurai/subset/nary_set_operator.hpp | 16 ++-- include/samurai/subset/projection.hpp | 4 +- include/samurai/subset/projection_loi.hpp | 31 ++++---- include/samurai/subset/set_base.hpp | 16 ++-- include/samurai/subset/translation.hpp | 15 +++- include/samurai/subset/utils.hpp | 78 ++++++++++++++++++++ 11 files changed, 153 insertions(+), 53 deletions(-) diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index d502acc7f..8e8372c0a 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -9,10 +9,10 @@ namespace samurai { namespace detail { - template + template void apply_rec(const SetBase& set, Func&& func, - Index& index, + typename SetBase::yz_index_t& yz_index, std::integral_constant d_ic, typename SetBase::Workspace& workspace) { @@ -21,19 +21,19 @@ namespace samurai set.init_workspace(1, d_ic, workspace); - for (traverser_t traverser = set.get_traverser(index, d_ic, workspace); !traverser.is_empty(); traverser.next_interval()) + for (traverser_t traverser = set.get_traverser(yz_index, d_ic, workspace); !traverser.is_empty(); traverser.next_interval()) { current_interval_t interval = traverser.current_interval(); if constexpr (d == 0) { - func(interval, index); + func(interval, yz_index); } else { - for (index[d - 1] = interval.start; index[d - 1] != interval.end; ++index[d - 1]) + for (yz_index[d - 1] = interval.start; yz_index[d - 1] != interval.end; ++yz_index[d - 1]) { - apply_rec(set, std::forward(func), index, std::integral_constant{}, workspace); + apply_rec(set, std::forward(func), yz_index, std::integral_constant{}, workspace); } } } @@ -43,15 +43,16 @@ namespace samurai template void apply(const SetBase& set, Func&& func) { - using Workspace = typename SetBase::Workspace; + using Workspace = typename Set::Workspace; + using yz_index_t = typename Set::yz_index_t; constexpr std::size_t dim = Set::dim; - xt::xtensor_fixed> index; + yz_index_t yz_index; if (set.exist()) { Workspace workspace; - detail::apply_rec(set, std::forward(func), index, std::integral_constant{}, workspace); + detail::apply_rec(set, std::forward(func), yz_index, std::integral_constant{}, workspace); } } } diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 33818713c..7c267868f 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -60,8 +60,8 @@ namespace samurai return !exist_impl(); } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant, Workspace) const + template + inline traverser_t get_traverser_impl(const yz_index_t& index, std::integral_constant, Workspace) const { return (m_box.min_corner()[d + 1] <= index[d] && index[d] < m_box.max_corner()[d + 1]) ? traverser_t(m_box.min_corner()[d], m_box.max_corner()[d]) diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index bc240beca..94e6d695b 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -93,8 +93,9 @@ namespace samurai m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + inline traverser_t + get_traverser_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { return traverser_t(m_set.get_traverser(index, d_ic, workspace.child_workspace), m_contraction[d]); } diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index c0825ae3b..93420622e 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -124,8 +124,9 @@ namespace samurai } } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + inline traverser_t + get_traverser_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { if constexpr (d == Base::dim - 1) { @@ -135,20 +136,21 @@ namespace samurai { auto& childTraversers = std::get(workspace.expansion_workspace); - xt::xtensor_fixed> tmp_index(index); + yz_index_t tmp_index(index); const auto childTraversers_begin = childTraversers.end(); for (value_t width = 0; width != m_expansions[d + 1] + 1; ++width) { - tmp_index[d + 1] = index[d + 1] + width; + // it's d and not d+1 because tmp_index represents m_expansions[1,..,dim] + tmp_index[d] = index[d] + width; childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { childTraversers.pop_back(); } - - tmp_index[d + 1] = index[d + 1] - width; + // same + tmp_index[d] = index[d] - width; childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 77cb5ea43..ab5f557aa 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -69,8 +69,8 @@ namespace samurai { } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant, Workspace& workspace) const + template + inline traverser_t get_traverser_impl(const yz_index_t& index, std::integral_constant, Workspace& workspace) const { if constexpr (d == Base::dim - 1) { diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 811879dc8..26850b15f 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -153,23 +153,25 @@ namespace samurai }); } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + inline traverser_t + get_traverser_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { return get_traverser_impl_detail(index, d_ic, std::make_index_sequence{}, workspace); } private: - template - traverser_t get_traverser_impl_detail(const index_t& index, + template + traverser_t get_traverser_impl_detail(const yz_index_t& index, std::integral_constant d_ic, std::index_sequence, Workspace& workspace) const { - return traverser_t( - m_shifts, - std::get(m_sets).get_traverser(index >> m_shifts[Is], d_ic, std::get(workspace.children_workspaces))...); + return traverser_t(m_shifts, + std::get(m_sets).get_traverser(utils::powMinus2(index, m_shifts[Is]), + d_ic, + std::get(workspace.children_workspaces))...); } Childrens m_sets; diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index a4014290e..52fa77558 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -109,9 +109,9 @@ namespace samurai m_set.init_workspace(my_work_size, d_ic, workspace.child_workspace); } - template + template inline traverser_t - get_traverser_impl(const index_t& _index, std::integral_constant d_ic, Workspace& workspace) const + get_traverser_impl(const yz_index_t& _index, std::integral_constant d_ic, Workspace& workspace) const { auto& childTraversers = std::get(workspace.projection_workspace); diff --git a/include/samurai/subset/projection_loi.hpp b/include/samurai/subset/projection_loi.hpp index 3dd14fd4a..4a6112781 100644 --- a/include/samurai/subset/projection_loi.hpp +++ b/include/samurai/subset/projection_loi.hpp @@ -8,6 +8,7 @@ #include "set_base.hpp" #include "traversers/last_dim_projection_loi_traverser.hpp" #include "traversers/projection_loi_traverser.hpp" +#include "utils.hpp" #include @@ -70,7 +71,6 @@ namespace samurai SAMURAI_SET_TYPEDEFS - using Index = xt::xtensor_fixed>; using ChildWorkspace = typename Set::Workspace; ProjectionLOI(const Set& set, const std::size_t level) @@ -113,8 +113,9 @@ namespace samurai m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + inline traverser_t + get_traverser_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { auto& listOfIntervals = std::get(workspace.projection_workspace); listOfIntervals.clear(); @@ -123,10 +124,10 @@ namespace samurai { if constexpr (d != Base::dim - 1) { - Index index_min(index << m_shift); - Index index_max((index + 1) << m_shift); + yz_index_t index_min(utils::pow2(index, m_shift)); + yz_index_t index_max(utils::sumAndPow2(index, 1, m_shift)); - Index index_rec; + yz_index_t index_rec; ChildWorkspace child_workspace; fill_list_of_interval_rec(index_min, index_max, @@ -136,27 +137,31 @@ namespace samurai child_workspace, workspace); - return traverser_t(m_set.get_traverser(index << m_shift, d_ic, workspace.child_workspace), + return traverser_t(m_set.get_traverser(utils::pow2(index, m_shift), d_ic, workspace.child_workspace), listOfIntervals.cbegin(), listOfIntervals.cend()); } else { - return traverser_t(m_set.get_traverser(index << m_shift, d_ic, workspace.child_workspace), m_projectionType, m_shift); + return traverser_t(m_set.get_traverser(utils::pow2(index, m_shift), d_ic, workspace.child_workspace), + m_projectionType, + m_shift); } } else { - return traverser_t(m_set.get_traverser(index >> m_shift, d_ic, workspace.child_workspace), m_projectionType, m_shift); + return traverser_t(m_set.get_traverser(utils::powMinus2(index, m_shift), d_ic, workspace.child_workspace), + m_projectionType, + m_shift); } } private: - template - inline void fill_list_of_interval_rec(const Index& index_min, - const Index& index_max, - index_t& index, + template + inline void fill_list_of_interval_rec(const yz_index_t& index_min, + const yz_index_t& index_max, + yz_index_t& index, std::integral_constant d_ic, std::integral_constant dCur_ic, ChildWorkspace& child_workspace, diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 32d953c0f..05334ba8c 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -56,6 +56,8 @@ namespace samurai using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; + using yz_index_t = xt::xtensor_fixed>; + using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; @@ -94,8 +96,8 @@ namespace samurai derived_cast().init_workspace_impl(n_traversers, d_ic, workspace); } - template - inline traverser_t get_traverser(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + inline traverser_t get_traverser(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { return derived_cast().get_traverser_impl(index, d_ic, workspace); } @@ -134,13 +136,13 @@ namespace samurai inline bool empty_default_impl() const { - xt::xtensor_fixed> index; + yz_index_t index; Workspace workspace; return empty_default_impl_rec(index, std::integral_constant{}, workspace); } - template - bool empty_default_impl_rec(index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + bool empty_default_impl_rec(yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { using current_interval_t = typename traverser_t::current_interval_t; @@ -179,7 +181,9 @@ namespace samurai using Workspace = typename Base::Workspace; \ \ using interval_t = typename Base::interval_t; \ - using value_t = typename Base::value_t; + using value_t = typename Base::value_t; \ + \ + using yz_index_t = typename Base::yz_index_t; template struct IsSet : std::bool_constant, T>::value> diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 4930c3f2e..201b2038d 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -74,11 +74,18 @@ namespace samurai m_set.init_workspace(n_traversers, d_ic, workspace.child_workspace); } - template - inline traverser_t get_traverser_impl(const index_t& index, std::integral_constant d_ic, Workspace& workspace) const + template + inline traverser_t + get_traverser_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { - return traverser_t(m_set.get_traverser_impl(index - xt::view(m_translation, xt::range(1, _)), d_ic, workspace.child_workspace), - m_translation[d]); + yz_index_t child_index; + + for (std::size_t i = 0; i != Base::dim - 1; ++i) + { + child_index[i] = index[i] - m_translation[i + 1]; + } + + return traverser_t(m_set.get_traverser_impl(child_index, d_ic, workspace.child_workspace), m_translation[d]); } private: diff --git a/include/samurai/subset/utils.hpp b/include/samurai/subset/utils.hpp index a45c1e1bb..dd621c8ed 100644 --- a/include/samurai/subset/utils.hpp +++ b/include/samurai/subset/utils.hpp @@ -49,6 +49,84 @@ namespace samurai } } + namespace utils + { + + template + std::array pow2(const std::array& input, const std::size_t shift = 1) + { + std::array output; + for (std::size_t i = 0; i != N; ++i) + { + output[i] = input[i] << shift; + } + + return output; + } + + template + std::array sumAndPow2(const std::array& input, const T& value, const std::size_t shift = 1) + { + std::array output; + for (std::size_t i = 0; i != N; ++i) + { + output[i] = (input[i] + value) << shift; + } + + return output; + } + + template + std::array powMinus2(const std::array& input, const std::size_t shift = 1) + { + std::array output; + for (std::size_t i = 0; i != N; ++i) + { + output[i] = input[i] >> shift; + } + + return output; + } + + template + xt::xtensor_fixed> pow2(const xt::xtensor_fixed>& input, const std::size_t shift = 1) + { + xt::xtensor_fixed> output; + for (std::size_t i = 0; i != N; ++i) + { + output[i] = input[i] << shift; + } + + return output; + } + + template + xt::xtensor_fixed> + sumAndPow2(const xt::xtensor_fixed>& input, const T& value, const std::size_t shift = 1) + { + xt::xtensor_fixed> output; + for (std::size_t i = 0; i != N; ++i) + { + output[i] = (input[i] + value) << shift; + } + + return output; + } + + template + xt::xtensor_fixed> powMinus2(const xt::xtensor_fixed>& input, const std::size_t shift = 1) + { + xt::xtensor_fixed> output; + for (std::size_t i = 0; i != N; ++i) + { + output[i] = input[i] >> shift; + } + + return output; + } + + } + //////////////////////////////////////////////////////////////////////// //// intervals args //////////////////////////////////////////////////////////////////////// From d5cd86b30e6391c61973c0f30fe696287bf2ddc9 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 15 Oct 2025 17:07:38 +0200 Subject: [PATCH 26/28] *-* --- include/samurai/samurai_config.hpp | 2 +- include/samurai/subset/apply.hpp | 6 +++++- include/samurai/subset/lca_view.hpp | 1 - include/samurai/subset/projection.hpp | 7 ++++--- include/samurai/subset/set_base.hpp | 8 +++++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/samurai/samurai_config.hpp b/include/samurai/samurai_config.hpp index ba0ebd361..fc8f32d87 100644 --- a/include/samurai/samurai_config.hpp +++ b/include/samurai/samurai_config.hpp @@ -20,7 +20,7 @@ namespace samurai static constexpr std::size_t graduation_width = 1; static constexpr std::size_t prediction_order = 1; - static constexpr bool prediction_with_list_of_intervals = true; + static constexpr bool projection_with_list_of_intervals = false; using index_t = signed long long int; using value_t = int; diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index 8e8372c0a..5307955a1 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -27,7 +27,11 @@ namespace samurai if constexpr (d == 0) { - func(interval, yz_index); + using tensor = typename Set::xt_yz_index_t; + tensor tensor_yz_index; + std::copy(yz_index.cbegin(), yz_index.cend(), tensor_yz_index.begin()); + + func(interval, tensor_yz_index); } else { diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index ab5f557aa..3a64329d4 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -101,7 +101,6 @@ namespace samurai if (z_interval_it == end_z_interval) { - y_start_offset = y_end_offset; return traverser_t(y_intervals.cend(), y_intervals.cend()); } const auto& y_offsets = m_lca.offsets(d + 1); diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index 52fa77558..e5cc36842 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -7,6 +7,7 @@ #include "../static_algorithm.hpp" #include "set_base.hpp" #include "traversers/projection_traverser.hpp" +#include "utils.hpp" namespace samurai { @@ -124,7 +125,7 @@ namespace samurai const value_t ymin = _index[d] << m_shift; const value_t ybound = (_index[d] + 1) << m_shift; - xt::xtensor_fixed> index(_index << m_shift); + yz_index_t index(utils::pow2(_index, m_shift)); const auto childTraversers_begin = childTraversers.end(); @@ -143,13 +144,13 @@ namespace samurai } else { - childTraversers.push_back(m_set.get_traverser(_index << m_shift, d_ic, workspace.child_workspace)); + childTraversers.push_back(m_set.get_traverser(utils::pow2(_index, m_shift), d_ic, workspace.child_workspace)); return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } else { - childTraversers.push_back(m_set.get_traverser(_index >> m_shift, d_ic, workspace.child_workspace)); + childTraversers.push_back(m_set.get_traverser(utils::powMinus2(_index, m_shift), d_ic, workspace.child_workspace)); return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 05334ba8c..a23cbeb5c 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -56,12 +56,13 @@ namespace samurai using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; - using yz_index_t = xt::xtensor_fixed>; + using yz_index_t = std::array; + using xt_yz_index_t = xt::xtensor_fixed>; using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; - using ProjectionMethod = std::conditional_t, Projection>; + using ProjectionMethod = std::conditional_t, Projection>; static constexpr std::size_t dim = DerivedTraits::dim(); @@ -183,7 +184,8 @@ namespace samurai using interval_t = typename Base::interval_t; \ using value_t = typename Base::value_t; \ \ - using yz_index_t = typename Base::yz_index_t; + using yz_index_t = typename Base::yz_index_t; \ + using xt_yz_index_t = typename Base::xt_yz_index_t; template struct IsSet : std::bool_constant, T>::value> From 718cd983d7d1f5fdb6c6f6cf738b1734603f33e7 Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Wed, 15 Oct 2025 17:08:58 +0200 Subject: [PATCH 27/28] *-* --- include/samurai/subset/apply.hpp | 6 +----- include/samurai/subset/set_base.hpp | 7 +++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index 5307955a1..8e8372c0a 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -27,11 +27,7 @@ namespace samurai if constexpr (d == 0) { - using tensor = typename Set::xt_yz_index_t; - tensor tensor_yz_index; - std::copy(yz_index.cbegin(), yz_index.cend(), tensor_yz_index.begin()); - - func(interval, tensor_yz_index); + func(interval, yz_index); } else { diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index a23cbeb5c..769d89ce5 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -56,8 +56,8 @@ namespace samurai using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; - using yz_index_t = std::array; - using xt_yz_index_t = xt::xtensor_fixed>; + //~ using yz_index_t = std::array; + using yz_index_t = xt::xtensor_fixed>; using to_lca_t = LevelCellArray; using to_lca_coord_t = typename to_lca_t::coords_t; @@ -184,8 +184,7 @@ namespace samurai using interval_t = typename Base::interval_t; \ using value_t = typename Base::value_t; \ \ - using yz_index_t = typename Base::yz_index_t; \ - using xt_yz_index_t = typename Base::xt_yz_index_t; + using yz_index_t = typename Base::yz_index_t; template struct IsSet : std::bool_constant, T>::value> From b05bcfc8df1a4cd43da77a81b4fb1c423f9bc6fe Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Fri, 17 Oct 2025 12:42:47 +0200 Subject: [PATCH 28/28] lotta stuff --- include/samurai/subset/apply.hpp | 45 ++++++++++++- include/samurai/subset/box_view.hpp | 7 ++ include/samurai/subset/contraction.hpp | 7 ++ include/samurai/subset/expansion.hpp | 18 ++++- include/samurai/subset/lca_view.hpp | 70 +++++++++++++++++++ include/samurai/subset/nary_set_operator.hpp | 19 ++++++ include/samurai/subset/projection.hpp | 71 ++++++++++++++------ include/samurai/subset/projection_loi.hpp | 7 ++ include/samurai/subset/set_base.hpp | 10 ++- include/samurai/subset/translation.hpp | 14 ++++ tests/test_subset.cpp | 7 ++ 11 files changed, 248 insertions(+), 27 deletions(-) diff --git a/include/samurai/subset/apply.hpp b/include/samurai/subset/apply.hpp index 8e8372c0a..aef13b38d 100644 --- a/include/samurai/subset/apply.hpp +++ b/include/samurai/subset/apply.hpp @@ -18,12 +18,30 @@ namespace samurai { using traverser_t = typename Set::template traverser_t; using current_interval_t = typename traverser_t::current_interval_t; + using interval_t = typename traverser_t::interval_t; set.init_workspace(1, d_ic, workspace); - for (traverser_t traverser = set.get_traverser(yz_index, d_ic, workspace); !traverser.is_empty(); traverser.next_interval()) + //~for (traverser_t traverser = set.get_traverser(yz_index, d_ic, workspace); !traverser.is_empty(); traverser.next_interval()) + //~{ + //~ current_interval_t interval = traverser.current_interval(); + //~ + //~ if constexpr (d == 0) + //~ { + //~ func(interval, yz_index); + //~ } + //~ else + //~ { + //~ for (yz_index[d - 1] = interval.start; yz_index[d - 1] != interval.end; ++yz_index[d - 1]) + //~ { + //~ apply_rec(set, std::forward(func), yz_index, std::integral_constant{}, workspace); + //~ } + //~ } + //~} + traverser_t traverser = set.get_traverser(yz_index, d_ic, workspace); + if (!traverser.is_empty()) { - current_interval_t interval = traverser.current_interval(); + interval_t interval = traverser.current_interval(); if constexpr (d == 0) { @@ -36,6 +54,29 @@ namespace samurai apply_rec(set, std::forward(func), yz_index, std::integral_constant{}, workspace); } } + traverser.next_interval(); + + while (!traverser.is_empty()) + { + interval_t old_interval = interval; + + interval = traverser.current_interval(); + + assert(old_interval < interval); + + if constexpr (d == 0) + { + func(interval, yz_index); + } + else + { + for (yz_index[d - 1] = interval.start; yz_index[d - 1] != interval.end; ++yz_index[d - 1]) + { + apply_rec(set, std::forward(func), yz_index, std::integral_constant{}, workspace); + } + } + traverser.next_interval(); + } } } } diff --git a/include/samurai/subset/box_view.hpp b/include/samurai/subset/box_view.hpp index 7c267868f..6ed4f10e5 100644 --- a/include/samurai/subset/box_view.hpp +++ b/include/samurai/subset/box_view.hpp @@ -68,6 +68,13 @@ namespace samurai : traverser_t(0, 0); } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace) const + { + return get_traverser_impl(index, d_ic, Workspace{}); + } + template inline constexpr void init_workspace_impl(const std::size_t, std::integral_constant, Workspace) const { diff --git a/include/samurai/subset/contraction.hpp b/include/samurai/subset/contraction.hpp index 94e6d695b..83e394293 100644 --- a/include/samurai/subset/contraction.hpp +++ b/include/samurai/subset/contraction.hpp @@ -100,6 +100,13 @@ namespace samurai return traverser_t(m_set.get_traverser(index, d_ic, workspace.child_workspace), m_contraction[d]); } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + return traverser_t(m_set.get_traverser_unordered(index, d_ic, workspace.child_workspace), m_contraction[d]); + } + private: Set m_set; diff --git a/include/samurai/subset/expansion.hpp b/include/samurai/subset/expansion.hpp index 93420622e..326bb7b63 100644 --- a/include/samurai/subset/expansion.hpp +++ b/include/samurai/subset/expansion.hpp @@ -144,14 +144,14 @@ namespace samurai { // it's d and not d+1 because tmp_index represents m_expansions[1,..,dim] tmp_index[d] = index[d] + width; - childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic, workspace.child_workspace)); + childTraversers.push_back(m_set.get_traverser_unordered(tmp_index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { childTraversers.pop_back(); } // same tmp_index[d] = index[d] - width; - childTraversers.push_back(m_set.get_traverser(tmp_index, d_ic, workspace.child_workspace)); + childTraversers.push_back(m_set.get_traverser_unordered(tmp_index, d_ic, workspace.child_workspace)); if (childTraversers.back().is_empty()) { childTraversers.pop_back(); @@ -162,6 +162,20 @@ namespace samurai } } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + if constexpr (d == Base::dim - 1) + { + return traverser_t(m_set.get_traverser_unordered(index, d_ic, workspace.child_workspace), m_expansions[d]); + } + else + { + return get_traverser_impl(index, d_ic, workspace); + } + } + private: Set m_set; diff --git a/include/samurai/subset/lca_view.hpp b/include/samurai/subset/lca_view.hpp index 3a64329d4..153656f3d 100644 --- a/include/samurai/subset/lca_view.hpp +++ b/include/samurai/subset/lca_view.hpp @@ -22,11 +22,18 @@ namespace samurai struct Workspace { + Workspace() + { + start_offset_guess.fill(0); + } + // we do not need the offsets for the last dim // the offset at dimension d will be initialized when calling // get_traverser_impl std::array start_offset; std::array end_offset; + + std::array start_offset_guess; }; static constexpr std::size_t dim() @@ -40,6 +47,8 @@ namespace samurai { using Self = LCAView; + using const_interval_iterator = typename std::vector::const_iterator; + public: SAMURAI_SET_TYPEDEFS @@ -101,6 +110,7 @@ namespace samurai if (z_interval_it == end_z_interval) { + y_start_offset = y_end_offset; return traverser_t(y_intervals.cend(), y_intervals.cend()); } const auto& y_offsets = m_lca.offsets(d + 1); @@ -112,6 +122,66 @@ namespace samurai } } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant, Workspace& workspace) const + { + ptrdiff_t start_offset = 0; + ptrdiff_t end_offset = std::ssize(m_lca[Base::dim - 1]); + + for (std::size_t dim = Base::dim - 1; dim != d; --dim) + { + const auto y = index[dim - 1]; + const auto& y_intervals = m_lca[dim]; + auto& start_offset_guess = workspace.start_offset_guess[dim - 1]; + + const auto begin_y_intervals = y_intervals.cbegin() + start_offset; + const auto end_y_intervals = y_intervals.cbegin() + end_offset; + const auto y_intervals_size = std::distance(begin_y_intervals, end_y_intervals); + // if guess was wrong for the higer dimensions, the guess is wrong an may even be out of [begin_y_intervals, + // end_y_intervals) we thus need to cap start_offset to ensure begin_y_intervals <= begin_y_intervals_guess <= + // end_y_intervals + const auto begin_y_intervals_guess = begin_y_intervals + std::min(start_offset, y_intervals_size); + + assert(begin_y_intervals <= begin_y_intervals_guess and begin_y_intervals_guess <= end_y_intervals); + + // we know the interval that contains y is likely to be in the range [begin_y_intervals_guess, end_y_intervals) + // first we try to find it within [begin_y_intervals_guess, end_y_intervals) + // hopefully, *begin_y_intervals_guess contains y. + auto y_interval_it = std::find_if(begin_y_intervals_guess, + end_y_intervals, + [y](const auto& y_interval) + { + return y_interval.contains(y); + }); + if (y_interval_it == end_y_intervals) + { + // we did not find an interval that contains y in [begin_y_intervals_guess, end_y_intervals) + // we try to find it in [begin_y_intervals, begin_y_intervals_guess) + y_interval_it = std::find_if(begin_y_intervals, + begin_y_intervals_guess, + [y](const auto& y_interval) + { + return y_interval.contains(y); + }); + if (y_interval_it == begin_y_intervals_guess) + { + // there is no interval that contains y + return traverser_t(m_lca[d].cend(), m_lca[d].cend()); + } + } + start_offset_guess = std::distance(begin_y_intervals, y_interval_it); + assert(0 <= start_offset_guess and start_offset_guess < std::distance(begin_y_intervals, end_y_intervals)); + + const auto& y_offsets = m_lca.offsets(dim); + const auto y_offset_idx = std::size_t(y + y_interval_it->index); + + start_offset = ptrdiff_t(y_offsets[y_offset_idx]); + end_offset = ptrdiff_t(y_offsets[y_offset_idx + 1]); + } + return traverser_t(m_lca[d].cbegin() + start_offset, m_lca[d].cbegin() + end_offset); + } + private: const LCA& m_lca; diff --git a/include/samurai/subset/nary_set_operator.hpp b/include/samurai/subset/nary_set_operator.hpp index 26850b15f..b9b99329f 100644 --- a/include/samurai/subset/nary_set_operator.hpp +++ b/include/samurai/subset/nary_set_operator.hpp @@ -160,6 +160,13 @@ namespace samurai return get_traverser_impl_detail(index, d_ic, std::make_index_sequence{}, workspace); } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + return get_traverser_unordered_impl_detail(index, d_ic, std::make_index_sequence{}, workspace); + } + private: template @@ -174,6 +181,18 @@ namespace samurai std::get(workspace.children_workspaces))...); } + template + traverser_t get_traverser_unordered_impl_detail(const yz_index_t& index, + std::integral_constant d_ic, + std::index_sequence, + Workspace& workspace) const + { + return traverser_t(m_shifts, + std::get(m_sets).get_traverser_unordered(utils::powMinus2(index, m_shifts[Is]), + d_ic, + std::get(workspace.children_workspaces))...); + } + Childrens m_sets; std::size_t m_level; std::array m_shifts; diff --git a/include/samurai/subset/projection.hpp b/include/samurai/subset/projection.hpp index e5cc36842..26d32a108 100644 --- a/include/samurai/subset/projection.hpp +++ b/include/samurai/subset/projection.hpp @@ -112,51 +112,78 @@ namespace samurai template inline traverser_t - get_traverser_impl(const yz_index_t& _index, std::integral_constant d_ic, Workspace& workspace) const + get_traverser_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { auto& childTraversers = std::get(workspace.projection_workspace); - if (m_projectionType == ProjectionType::COARSEN) { if constexpr (d != Base::dim - 1) { - const std::size_t old_capacity = childTraversers.capacity(); - - const value_t ymin = _index[d] << m_shift; - const value_t ybound = (_index[d] + 1) << m_shift; - - yz_index_t index(utils::pow2(_index, m_shift)); - const auto childTraversers_begin = childTraversers.end(); + fill_traverser_array(index, d_ic, workspace); + return traverser_t(childTraversers_begin, childTraversers.end(), m_shift); + } + else + { + childTraversers.push_back(m_set.get_traverser(utils::pow2(index, m_shift), d_ic, workspace.child_workspace)); + return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); + } + } + else + { + childTraversers.push_back(m_set.get_traverser(utils::powMinus2(index, m_shift), d_ic, workspace.child_workspace)); + return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); + } + } - for (index[d] = ymin; index[d] != ybound; ++index[d]) - { - childTraversers.push_back(m_set.get_traverser(index, d_ic, workspace.child_workspace)); - if (childTraversers.back().is_empty()) - { - childTraversers.pop_back(); - } - } - - assert(childTraversers.capacity() == old_capacity); - + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + auto& childTraversers = std::get(workspace.projection_workspace); + if (m_projectionType == ProjectionType::COARSEN) + { + if constexpr (d != Base::dim - 1) + { + const auto childTraversers_begin = childTraversers.end(); + fill_traverser_array(index, d_ic, workspace); return traverser_t(childTraversers_begin, childTraversers.end(), m_shift); } else { - childTraversers.push_back(m_set.get_traverser(utils::pow2(_index, m_shift), d_ic, workspace.child_workspace)); + childTraversers.push_back(m_set.get_traverser_unordered(utils::pow2(index, m_shift), d_ic, workspace.child_workspace)); return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } else { - childTraversers.push_back(m_set.get_traverser(utils::powMinus2(_index, m_shift), d_ic, workspace.child_workspace)); + childTraversers.push_back(m_set.get_traverser_unordered(utils::powMinus2(index, m_shift), d_ic, workspace.child_workspace)); return traverser_t(std::prev(childTraversers.end()), m_projectionType, m_shift); } } private: + template + void fill_traverser_array(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + auto& childTraversers = std::get(workspace.projection_workspace); + + const value_t ymin = index[d] << m_shift; + const value_t ybound = (index[d] + 1) << m_shift; + + yz_index_t projected_index(utils::pow2(index, m_shift)); + + for (projected_index[d] = ymin; projected_index[d] != ybound; ++projected_index[d]) + { + childTraversers.push_back(m_set.get_traverser_unordered(projected_index, d_ic, workspace.child_workspace)); + if (childTraversers.back().is_empty()) + { + childTraversers.pop_back(); + } + } + } + Set m_set; std::size_t m_level; ProjectionType m_projectionType; diff --git a/include/samurai/subset/projection_loi.hpp b/include/samurai/subset/projection_loi.hpp index 4a6112781..0c4fedc54 100644 --- a/include/samurai/subset/projection_loi.hpp +++ b/include/samurai/subset/projection_loi.hpp @@ -156,6 +156,13 @@ namespace samurai } } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + return get_traverser_impl(index, d_ic, workspace); + } + private: template diff --git a/include/samurai/subset/set_base.hpp b/include/samurai/subset/set_base.hpp index 769d89ce5..5c4d2e0e1 100644 --- a/include/samurai/subset/set_base.hpp +++ b/include/samurai/subset/set_base.hpp @@ -56,7 +56,6 @@ namespace samurai using interval_t = typename traverser_t<0>::interval_t; using value_t = typename interval_t::value_t; - //~ using yz_index_t = std::array; using yz_index_t = xt::xtensor_fixed>; using to_lca_t = LevelCellArray; @@ -97,12 +96,21 @@ namespace samurai derived_cast().init_workspace_impl(n_traversers, d_ic, workspace); } + //// Only works for increasing index template inline traverser_t get_traverser(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const { return derived_cast().get_traverser_impl(index, d_ic, workspace); } + //// Works for random indexes but might be slower + template + inline traverser_t + get_traverser_unordered(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + return derived_cast().get_traverser_unordered_impl(index, d_ic, workspace); + } + inline ProjectionMethod on(const std::size_t level); template diff --git a/include/samurai/subset/translation.hpp b/include/samurai/subset/translation.hpp index 201b2038d..4cc5fd3a3 100644 --- a/include/samurai/subset/translation.hpp +++ b/include/samurai/subset/translation.hpp @@ -88,6 +88,20 @@ namespace samurai return traverser_t(m_set.get_traverser_impl(child_index, d_ic, workspace.child_workspace), m_translation[d]); } + template + inline traverser_t + get_traverser_unordered_impl(const yz_index_t& index, std::integral_constant d_ic, Workspace& workspace) const + { + yz_index_t child_index; + + for (std::size_t i = 0; i != Base::dim - 1; ++i) + { + child_index[i] = index[i] - m_translation[i + 1]; + } + + return traverser_t(m_set.get_traverser_unordered_impl(child_index, d_ic, workspace.child_workspace), m_translation[d]); + } + private: Set m_set; diff --git a/tests/test_subset.cpp b/tests/test_subset.cpp index 3171b246c..2239eb87b 100644 --- a/tests/test_subset.cpp +++ b/tests/test_subset.cpp @@ -1304,6 +1304,13 @@ namespace samurai ca = {cl, true}; + //~ std::cout << "===========================================" << std::endl; + //~ std::cout << ca[4] << std::endl; + //~ std::cout << "===========================================" << std::endl; + //~ std::cout << self(ca[4]).on(3).to_lca() << std::endl; + //~ std::cout << "===========================================" << std::endl; + //~ std::exit(0); + // Test self-similarity at different scales bool found = false; apply(intersection(ca[3], self(ca[4]).on(3)),