diff --git a/amdis/common/Apply.hpp b/amdis/common/Apply.hpp index 195c90a5212073d116b8aa02767fe0289dc01269..0813bf6326b4bab1f7f152e0d85729cd8e77a38f 100644 --- a/amdis/common/Apply.hpp +++ b/amdis/common/Apply.hpp @@ -10,19 +10,19 @@ namespace AMDiS { - namespace Tools + namespace Ranges { namespace Impl_ { template - constexpr decltype(auto) apply_impl(Functor&& f, Tuple&& t, std::index_sequence) + constexpr decltype(auto) applyImpl(Functor&& f, Tuple&& t, std::index_sequence) { using std::get; return f(get(FWD(t))...); } template - constexpr decltype(auto) apply_indices_impl(Functor&& f, index_t, std::index_sequence) + constexpr decltype(auto) applyIndicesImpl(Functor&& f, index_t, std::index_sequence) { return f(index_t{}...); } @@ -31,35 +31,44 @@ namespace AMDiS template constexpr decltype(auto) apply(F&& f, Tuple&& t) { - return Impl_::apply_impl(FWD(f), FWD(t), + return Impl_::applyImpl(FWD(f), FWD(t), std::make_index_sequence>{}); } template - constexpr decltype(auto) apply_variadic(Functor&& f, Args&&... args) + constexpr decltype(auto) applyVariadic(Functor&& f, Args&&... args) { - return apply(FWD(f), std::forward_as_tuple(args...)); + return Impl_::applyImpl(FWD(f), std::forward_as_tuple(args...), + std::make_index_sequence{}); } template - constexpr decltype(auto) apply_indices(Functor&& f) + constexpr decltype(auto) applyIndices(Functor&& f) { - return Impl_::apply_indices_impl(FWD(f), index_t<0>{}, + return Impl_::applyIndicesImpl(FWD(f), index_t<0>{}, std::make_index_sequence{}); } + template + constexpr decltype(auto) applyIndices(Functor&& f) + { + return Impl_::applyIndicesImpl(FWD(f), index_t{}, + std::make_index_sequence{}); + } + template - constexpr decltype(auto) apply_indices(Functor&& f, index_t) + constexpr decltype(auto) applyIndices(Functor&& f, index_t) { - return Impl_::apply_indices_impl(FWD(f), index_t<0>{}, + return Impl_::applyIndicesImpl(FWD(f), index_t<0>{}, std::make_index_sequence{}); } template - constexpr decltype(auto) apply_indices(Functor&& f, index_t, index_t) + constexpr decltype(auto) applyIndices(Functor&& f, index_t, index_t) { - return Impl_::apply_indices_impl(FWD(f), index_t{}, + return Impl_::applyIndicesImpl(FWD(f), index_t{}, std::make_index_sequence{}); } - } + + } // end namespace Ranges } // end namespace AMDiS diff --git a/amdis/common/CMakeLists.txt b/amdis/common/CMakeLists.txt index 287bd96128aa5f0fa0fcf9375e464ad8da02c5ed..dbfb901d490fed9c34681a2f37c3b69cb819ef5a 100644 --- a/amdis/common/CMakeLists.txt +++ b/amdis/common/CMakeLists.txt @@ -24,6 +24,8 @@ install(FILES Math.hpp Order.hpp Range.hpp + RecursiveApply.hpp + RecursiveForEach.hpp QuadMath.hpp SharedPtr.hpp StaticSize.hpp diff --git a/amdis/common/ForEach.hpp b/amdis/common/ForEach.hpp index 463740ecfdba655c474fee71f4e87ff6c242eb25..5477ab71506c8a7c9ebff34591a1c42f51e2bd40 100644 --- a/amdis/common/ForEach.hpp +++ b/amdis/common/ForEach.hpp @@ -7,36 +7,36 @@ namespace AMDiS { - namespace Tools + namespace Ranges { template - constexpr void for_variadic(Functor&& f, Args&&... args) + constexpr void forVariadic(Functor&& f, Args&&... args) { (f(FWD(args)),...); } template - constexpr void for_each(std::index_sequence, Tuple&& tuple, Functor&& f) + constexpr void forEach(std::index_sequence, Tuple&& tuple, Functor&& f) { using std::get; (f(get(tuple)),...); } template - constexpr void for_each(Tuple&& tuple, Functor&& f) + constexpr void forEach(Tuple&& tuple, Functor&& f) { - Tools::for_each(std::make_index_sequence>{}, FWD(tuple), FWD(f)); + Ranges::forEach(std::make_index_sequence>{}, FWD(tuple), FWD(f)); } template - constexpr void for_each(std::array const& a, Functor&& f) + constexpr void forEach(std::array const& a, Functor&& f) { for (auto const& ai : a) f(ai); } template - constexpr void for_each(std::vector const& v, Functor&& f) + constexpr void forEach(std::vector const& v, Functor&& f) { for (auto const& vi : v) f(vi); @@ -44,28 +44,34 @@ namespace AMDiS template - constexpr void for_range(std::index_sequence, Functor&& f) + constexpr void forIndices(std::index_sequence, Functor&& f) { (f(index_t{}),...); } template - constexpr void for_range(index_t, index_t, Functor&& f) + constexpr void forIndices(index_t, index_t, Functor&& f) { - Tools::for_range(std::make_index_sequence{}, FWD(f)); + Ranges::forIndices(std::make_index_sequence{}, FWD(f)); } template - constexpr void for_range(index_t, Functor&& f) + constexpr void forIndices(index_t, Functor&& f) { - Tools::for_range(std::make_index_sequence{}, FWD(f)); + Ranges::forIndices(std::make_index_sequence{}, FWD(f)); } template - constexpr void for_range(Functor&& f) + constexpr void forIndices(Functor&& f) { - Tools::for_range(std::make_index_sequence{}, FWD(f)); + Ranges::forIndices(std::make_index_sequence{}, FWD(f)); } - } // end namespace Tools + template + constexpr void forIndices(Functor&& f) + { + Ranges::forIndices<0>(std::make_index_sequence{}, FWD(f)); + } + + } // end namespace Ranges } // end namespace AMDiS diff --git a/amdis/common/RecursiveApply.hpp b/amdis/common/RecursiveApply.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5632547f3fc5dd586f397bf7d4a9cf9460c84323 --- /dev/null +++ b/amdis/common/RecursiveApply.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace AMDiS +{ + namespace Recursive + { + /// Default implementation of the recursive \ref map function. + template + struct Apply + { + template + static auto impl(F&& f, T const& t) + { + return f(t); + } + }; + + /// \brief Recursive application of a transformation functor `f` to a hierarchic + /// container of containers, returning the transformed container. + /** + * This utility function applies the given functor `f` to the "leaf" entries in + * a hierarchic container that returns a transformed container. Therefore, the + * container is traversed recursively, using specializations of the `Map::apply` + * class method. If no specialization is provided, the function is applied to the + * whole container or leaf entry, respectively. + **/ + template + auto apply(F&& f, T const& t) + { + return Apply::impl(f,t); + } + + + // specializations for container types + + template + struct Apply> + { + template + static auto impl(F&& f, std::array const& a) + { + return Ranges::applyIndices([&](auto... ii) { + return std::array{Recursive::apply(f,a[ii])...}; }); + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, std::tuple const& t) + { + return Ranges::apply([&](auto const&... ti) { + return std::tuple{Recursive::apply(f,ti)...}; }, t); + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, std::pair const& t) + { + return std::pair{Recursive::apply(f,t.first), + Recursive::apply(f,t.second)}; + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, Dune::TupleVector const& t) + { + return Ranges::apply([&](auto const&... ti) { + return Dune::makeTupleVector(Recursive::apply(f,ti)...); }, t); + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, std::vector const& v) + { + using U = TYPEOF(Recursive::apply(f,std::declval())); + std::vector out; + out.reserve(v.size()); + for (std::size_t i = 0; i < v.size(); ++i) + out.emplace_back(Recursive::apply(f,v[i])); + return out; + } + }; + + } // end namespace Recursive +} // end namespace AMDiS \ No newline at end of file diff --git a/amdis/common/RecursiveForEach.hpp b/amdis/common/RecursiveForEach.hpp new file mode 100644 index 0000000000000000000000000000000000000000..177cc52a5f1921fdd63ce65a8580281f3ea98641 --- /dev/null +++ b/amdis/common/RecursiveForEach.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace AMDiS +{ + namespace Recursive + { + /// Default implementation of the recursive \ref forEach function. + /** + * \tparam V The type of the container/value decayed to the raw type + **/ + template + struct ForEach + { + template + static void impl(Value&& v, F&& f) + { + f(v); + } + }; + + /// \brief Recursive application of a functor `f` to a hierarchic container of containers. + /** + * This utility function applies the given functor `f` to the "leaf" entries in + * a hierarchic container. Therefore, the container is traversed recursively, + * using specializations of the `ForEach::apply` class method. + * If no specialization is provided, the function is applied to the whole container + * or leaf entry, respectively. + **/ + template + void forEach(Container&& container, F&& f) + { + ForEach::impl(container,f); + } + + + // specializations for container types + + template + struct ForEach> + { + using indices = std::make_index_sequence; + + template + static void impl2(std::index_sequence, Tuple&& tuple, F&& f) + { + using std::get; + (Recursive::forEach(get(tuple), f),...); + } + + template + static void impl(Tuple&& tuple, F&& f) + { + impl2(indices{}, tuple, f); + } + }; + + template + struct ForEach> + { + template + static void impl(Pair&& pair, F&& f) + { + Recursive::forEach(pair.first, f); + Recursive::forEach(pair.second, f); + } + }; + + template + struct ForEach> + { + template + static void impl(Tuple&& tuple, F&& f) + { + ForEach>::impl(tuple, f); + } + }; + + template + struct ForEach> + { + template + static void impl(Array&& a, F&& f) + { + for (auto&& ai : a) + Recursive::forEach(ai, f); + } + }; + + template + struct ForEach> + { + template + static void impl(Vector&& v, F&& f) + { + for (auto&& vi : v) + Recursive::forEach(vi, f); + } + }; + + } // end namespace Recursive +} // end namespace AMDiS diff --git a/amdis/functions/GlobalIdSet.hpp b/amdis/functions/GlobalIdSet.hpp index fa74670e52c500d2140d6f30985a6318f7bdcd12..c3f745a76e1207d8f4e92aea147d08ca8114f742 100644 --- a/amdis/functions/GlobalIdSet.hpp +++ b/amdis/functions/GlobalIdSet.hpp @@ -370,7 +370,7 @@ namespace AMDiS public: NodeIdSet(GridView const& gridView) - : idsTuple_(Tools::apply_indices([&](auto... i) { + : idsTuple_(Ranges::applyIndices([&](auto... i) { return std::make_tuple(SubNodeIdSet(gridView)...); })) {} @@ -379,7 +379,7 @@ namespace AMDiS void bind(const Node& node) { node_ = &node; - Tools::for_range<0,children>([&](auto i) { + Ranges::forIndices<0,children>([&](auto i) { std::get(idsTuple_).bind(node.child(i)); }); } @@ -388,7 +388,7 @@ namespace AMDiS void unbind() { node_ = nullptr; - Tools::for_each(idsTuple_, [](auto& ids) { + Ranges::forEach(idsTuple_, [](auto& ids) { ids.unbind(); }); } @@ -404,7 +404,7 @@ namespace AMDiS It fillIn(Twist const& twist, It it, size_type shift = 0) const { assert(node_ != nullptr); - Tools::for_each(idsTuple_, [&](auto const& ids) + Ranges::forEach(idsTuple_, [&](auto const& ids) { size_type subTreeSize = ids.size(); it = ids.fillIn(twist, it, shift); diff --git a/amdis/functions/HierarchicNodeToRangeMap.hpp b/amdis/functions/HierarchicNodeToRangeMap.hpp index 1f5ff7b7e19693769b28e60ee496f7ce94862523..7e89be5cd83753cabde81324d39c01934db96993 100644 --- a/amdis/functions/HierarchicNodeToRangeMap.hpp +++ b/amdis/functions/HierarchicNodeToRangeMap.hpp @@ -51,7 +51,7 @@ namespace AMDiS template static auto transformTreePath(TreePath const& treePath) { - return Tools::apply([](auto... i) { return Dune::makeTupleVector(i...); }, treePath._data); + return Ranges::apply([](auto... i) { return Dune::makeTupleVector(i...); }, treePath._data); } #endif }; diff --git a/amdis/functions/Order.hpp b/amdis/functions/Order.hpp index 622ff5cd90108353b5fee4d97b2a21df74638c96..5575bd4351bb156d38d2e60caafc8e0dfa5fc9f9 100644 --- a/amdis/functions/Order.hpp +++ b/amdis/functions/Order.hpp @@ -16,7 +16,7 @@ namespace AMDiS else if constexpr (N::isPower) return order(node.child(0u)); else if constexpr (N::isComposite) - return Tools::apply_indices([&](auto... ii) { + return Ranges::applyIndices([&](auto... ii) { return Math::max(order(node.child(ii))...); }); else { diff --git a/amdis/gridfunctions/FunctorGridFunction.hpp b/amdis/gridfunctions/FunctorGridFunction.hpp index b24b0025dcc86f569204b6c50d7f1f9b3e639940..d9992d4a0bdbe24609e6f3d4a5902018f0f4fbb3 100644 --- a/amdis/gridfunctions/FunctorGridFunction.hpp +++ b/amdis/gridfunctions/FunctorGridFunction.hpp @@ -72,7 +72,7 @@ namespace AMDiS template void bind(Element const& element) { - Tools::for_each(localFcts_, [&](auto& localFct) { + Ranges::forEach(localFcts_, [&](auto& localFct) { (*localFct).bind(element); }); } @@ -80,7 +80,7 @@ namespace AMDiS /// Calls \ref unbind for all localFunctions void unbind() { - Tools::for_each(localFcts_, [&](auto& localFct) { + Ranges::forEach(localFcts_, [&](auto& localFct) { (*localFct).unbind(); }); } @@ -88,7 +88,7 @@ namespace AMDiS /// Applies the functor \ref fct_ to the evaluated localFunctions Range operator()(Domain const& x) const { - return Tools::apply([&](auto&&... localFct) { return fct_((*localFct)(x)...); }, localFcts_); + return Ranges::apply([&](auto&&... localFct) { return fct_((*localFct)(x)...); }, localFcts_); } public: @@ -127,7 +127,7 @@ namespace AMDiS // d_i(f)[lgfs...] * lgfs_i auto term_i = [&](auto const _i) { - auto di_f = Tools::apply([&](auto const&... lgfs) { + auto di_f = Ranges::apply([&](auto const&... lgfs) { return makeFunctorGridFunction(partial(lf.fct(), _i), (*lgfs)...); }, lf.localFcts()); @@ -137,7 +137,7 @@ namespace AMDiS }; // sum_i [ d_i(f)[lgfs...] * derivativeOf(lgfs_i) - auto gridFct = Tools::apply([&](auto const... _i) + auto gridFct = Ranges::apply([&](auto const... _i) { return makeFunctorGridFunction(Operation::Plus{}, term_i(_i)...); }, index_seq); @@ -159,7 +159,7 @@ namespace AMDiS && (Concepts::Polynomial &&...))> int order(FunctorLocalFunction const& lf) { - return Tools::apply([&lf](auto const&... lgfs) { + return Ranges::apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(*lgfs)...); }, lf.localFcts()); } @@ -216,7 +216,7 @@ namespace AMDiS /// Applies the functor to the evaluated gridfunctions Range operator()(Domain const& x) const { - return Tools::apply([&](auto&&... gridFct) { return fct_(gridFct(x)...); }, gridFcts_); + return Ranges::apply([&](auto&&... gridFct) { return fct_(gridFct(x)...); }, gridFcts_); } /// Return the stored \ref EntitySet of the first GridFunction @@ -227,7 +227,7 @@ namespace AMDiS LocalFunction makeLocalFunction() const { - return Tools::apply([&](auto const&... gridFcts) { return LocalFunction{fct_, gridFcts...}; }, gridFcts_); + return Ranges::apply([&](auto const&... gridFcts) { return LocalFunction{fct_, gridFcts...}; }, gridFcts_); } private: @@ -260,7 +260,7 @@ namespace AMDiS template static auto create(Self const& self, GridView const& gridView) { - return Tools::apply([&](auto const&... pgf) { + return Ranges::apply([&](auto const&... pgf) { return makeFunctorGridFunction(self.fct_, makeGridFunction(pgf, gridView)...); }, self.preGridFcts_); diff --git a/amdis/operations/Composer.hpp b/amdis/operations/Composer.hpp index 93481cfc926103cade8a76320503515d85519a53..12e3341619365351c63ceace58391de062d66ea8 100644 --- a/amdis/operations/Composer.hpp +++ b/amdis/operations/Composer.hpp @@ -41,7 +41,7 @@ namespace AMDiS constexpr auto operator()(Ts const&... args) const { auto eval = [&](auto const& g) { return g(args...); }; - return Tools::apply([&,this](auto const&... gs) { return f_(eval(gs)...); }, gs_); + return Ranges::apply([&,this](auto const&... gs) { return f_(eval(gs)...); }, gs_); } F f_; @@ -76,7 +76,7 @@ namespace AMDiS int order(Composer const& c, Int... degrees) { auto deg = [&](auto const& g) { return order(g, int(degrees)...); }; - return Tools::apply([&](auto const&... gs) { return order(c.f_, deg(gs)...); }, c.gs_); + return Ranges::apply([&](auto const&... gs) { return order(c.f_, deg(gs)...); }, c.gs_); } /// Partial derivative of composed function: diff --git a/amdis/typetree/CMakeLists.txt b/amdis/typetree/CMakeLists.txt index ccabc420345261ea015a9158085de957e07bf5d4..fd487042785e6b0e0d82116fc63eb6b882f1c096 100644 --- a/amdis/typetree/CMakeLists.txt +++ b/amdis/typetree/CMakeLists.txt @@ -6,5 +6,6 @@ install(FILES Traits.hpp Traversal.hpp TreeContainer.hpp + TreeContainerTransformation.hpp TreePath.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/typetree) diff --git a/amdis/typetree/TreeContainer.hpp b/amdis/typetree/TreeContainer.hpp index 159cb14cf0f6ab99b12ce8e55bc249d0037fe7c5..c0accf758c504f5642a06ffdeaf4bf178cd7ba23 100644 --- a/amdis/typetree/TreeContainer.hpp +++ b/amdis/typetree/TreeContainer.hpp @@ -259,7 +259,7 @@ namespace AMDiS if constexpr (Node::isComposite) { return ValueAndContainer{ value(node), - Tools::apply_indices( + Ranges::applyIndices( [&](auto... ii) { return Dune::makeTupleVector((*this)(node.child(ii))...); })}; } else { diff --git a/amdis/typetree/TreeContainerTransformation.hpp b/amdis/typetree/TreeContainerTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..72010010a5e6b09f0a4da6095939342ec6e0fc3e --- /dev/null +++ b/amdis/typetree/TreeContainerTransformation.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include + +namespace AMDiS +{ + namespace Recursive + { + // specializations of recursive utilities for TreeContainer entries + + template <> + struct Apply + { + template + static auto impl(F&& /*f*/, Impl::Ignore) + { + return Impl::Ignore{}; + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, VC const& vc) + { + return Impl::ValueAndContainer{ + Recursive::apply(f,vc.value()), + Recursive::apply(f,vc.container())}; + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, VC const& vc) + { + return Impl::ValueAndContainer{Recursive::apply(f,vc.value())}; + } + }; + + template + struct Apply> + { + template + static auto impl(F&& f, TC const& c) + { + return TreeContainerStorage{Recursive::apply(f,c.data())}; + } + }; + + // ------------------------------------------------------------------------- + + template <> + struct ForEach + { + template + static void impl(Impl::Ignore, F&& /*f*/) {} + }; + + template + struct ForEach> + { + template + static void impl(VC&& vc, F&& f) + { + Recursive::forEach(vc.value(),f); + Recursive::forEach(vc.container(),f); + } + }; + + template + struct ForEach> + { + template + static void impl(VC&& vc, F&& f) + { + Recursive::forEach(vc.value(),f); + } + }; + + template + struct ForEach> + { + template + static void impl(TC&& c, F&& f) + { + Recursive::forEach(c.data(),f); + } + }; + + } // end namespace Tools +} // end namespace AMDiS diff --git a/test/PETScCommTest.cpp b/test/PETScCommTest.cpp index e712e6d8296d05e84b445f33ba6b8a530da99947..94ec26b4a88693562a0acf89d9440c9683d612be 100644 --- a/test/PETScCommTest.cpp +++ b/test/PETScCommTest.cpp @@ -97,7 +97,7 @@ void test_grid(std::string gridName) allSimplex = allSimplex && type.isSimplex(); // continuouse basis - Tools::for_range<1,4>([&](auto const k) { + Ranges::forIndices<1,4>([&](auto const k) { if (allSimplex || k < 3) { using namespace Dune::Functions::BasisFactory; auto basis = makeBasis(gv, lagrange()); @@ -106,7 +106,7 @@ void test_grid(std::string gridName) }); // discontinuous basis - Tools::for_range<1,5>([&](auto const k) { + Ranges::forIndices<1,5>([&](auto const k) { using namespace Dune::Functions::BasisFactory; auto basis = makeBasis(gv, lagrangeDG()); test_basis(basis, gridName, "lagrangeDG<" + std::to_string(k.value) + ">"); diff --git a/test/ParallelIndexSetTest.cpp b/test/ParallelIndexSetTest.cpp index c4739cf15f3d8af1b7bd09210def567c9dab4bdc..56c5dde41b2c202a3af725484d7cdec870f6354b 100644 --- a/test/ParallelIndexSetTest.cpp +++ b/test/ParallelIndexSetTest.cpp @@ -121,7 +121,7 @@ void test_grid(std::string gridName) allSimplex = allSimplex && type.isSimplex(); // continuouse basis - Tools::for_range<1,4>([&](auto const k) { + Ranges::forIndices<1,4>([&](auto const k) { if (allSimplex || k < 3) { using namespace Dune::Functions::BasisFactory; auto basis = makeBasis(gv, lagrange()); @@ -130,7 +130,7 @@ void test_grid(std::string gridName) }); // discontinuous basis - Tools::for_range<1,5>([&](auto const k) { + Ranges::forIndices<1,5>([&](auto const k) { using namespace Dune::Functions::BasisFactory; auto basis = makeBasis(gv, lagrangeDG()); test_basis(basis, gridName, "lagrangeDG<" + std::to_string(k.value) + ">"); diff --git a/test/RecursiveTest.cpp b/test/RecursiveTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34db0007bd50107f8fbdad5b3762ae65e0f42040 --- /dev/null +++ b/test/RecursiveTest.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +#include "Tests.hpp" + +using namespace AMDiS; + +template +void test(Container& container) +{ + // initialize container + int i = 0; + Recursive::forEach(container, [&](auto& c) { c = i++; }); + + // sum up all the elements recursively + int sum = 0; + Recursive::forEach(container, [&](auto const& c) { sum += c; }); + + // create a new container with scaled elements + auto scaled = Recursive::apply([&](auto const& c) { return 2*c; }, container); + + // sum up agains + int sum2 = 0; + Recursive::forEach(scaled, [&](auto const& c) { sum2 += c; }); + + AMDIS_TEST_EQ(2*sum, sum2); +} + +int main(int argc, char** argv) +{ + Environment env(argc, argv); + + std::vector,2>> container1(2); + test(container1); + + std::tuple,2>> container2; + std::get<0>(container2)[0].resize(2); + std::get<0>(container2)[1].resize(2); + test(container2); + + return report_errors(); +} \ No newline at end of file