dune-typetree merge requestshttps://gitlab.dune-project.org/staging/dune-typetree/-/merge_requests2023-01-19T12:55:02Zhttps://gitlab.dune-project.org/staging/dune-typetree/-/merge_requests/122Add operator/ to join treepaths2023-01-19T12:55:02ZSimon PraetoriusAdd operator/ to join treepaths### Summary
Based on the discussion in !109 this MR adds an `operator/` to concatenate treepaths with other treepaths or indices.
### Example
```c++
auto tp1 = treePath(0,1) / 2; // == treepath(0,1,2)
auto tp2 = 2_tp / treePath(1,_0...### Summary
Based on the discussion in !109 this MR adds an `operator/` to concatenate treepaths with other treepaths or indices.
### Example
```c++
auto tp1 = treePath(0,1) / 2; // == treepath(0,1,2)
auto tp2 = 2_tp / treePath(1,_0); // == treePath(_2,1,_0)
```https://gitlab.dune-project.org/staging/dune-typetree/-/merge_requests/111WIP: A new implementation of type-tree2022-10-24T12:12:19ZSimon PraetoriusWIP: A new implementation of type-tree## Summary
This is an experiment to replace the old structures of a typetree with a new implementation more similar to the TreeContainer in dune-functions, i.e., a direct composition of `std::array`, `std::tuple` and `std::vector`.
## ...## Summary
This is an experiment to replace the old structures of a typetree with a new implementation more similar to the TreeContainer in dune-functions, i.e., a direct composition of `std::array`, `std::tuple` and `std::vector`.
## Proposal
This MR proposes to unify the multiple type-tree implementations we are currently using or that are proposed. In dune-functions we currently have at least 2 type-trees: The basis-tree and the tree-container. Both with different purpose and both with different interface. Both need hierarchic traversal/access and size/resize utilities. In staging/dune-functions!350 a third tree is proposed, again with the same requirements, but encoding something different. Actually, there are more trees hidden: The basis tree is basically a combination of two trees, a localbasis tree and an index tree.
The proposed TypeTree a data-structures are flexible enough to represent all these trees, with a simple and efficient storage, access, traversal and transformation. It is possible to transform a basis-tree into a tree-container, or a basis-tree into a size-tree... with a not too complicated utility. A generic tree-transform function is provided and the corresponding test from dune-typetree are passing.
### Details
The type-tree is based on a composition of `std::array` for static-size uniform-type nodes, `std::tuple` for non-uniform-type nodes, `std::vector` for dynamic-size uniform-type nodes, and two special nodes in case all the children are exactly identical.
The tree nodes encode the three properties:
1. type uniformity (`isTypeUniform`)
1. value uniformity, i.e. whether all childs are identical (`isUniform`)
1. whether this size is statically known (`hasStaticSize`)
The names of the nodes try to encode these properties, but are up to discussion, see below.
The tree nodes are derived from the corresponding std containers, thus provide typically an `operator[](index)` access and a `size()` method. This is not the public interface, but the corresponding methods `child(index)` and `degree()`. But, the base-class methods are not hidden, meaning they can be used e.g. in a tree-container interface.
## Differences to old implementation
* TypeTree is a direct composition of `std::array`, `std::vector` and `Dune::TupleVector` + some lightweight nodes for uniform childs
* Nodes are stored by value and not as `shared_ptr`. (this might be a discussion point)
* A TreeContainer is just a Tree with its `LeafNode` replaced by a corresponding value type.
* Traversal and child access as before with no change
* Tree container vector-backend can use standard tree traversal and access. Resize method can be simplified a lot.https://gitlab.dune-project.org/staging/dune-typetree/-/merge_requests/86Make visitor the responsible for choosing traversal strategy2021-02-18T10:50:25ZSantiago Ospina De Los Ríossospinar@gmail.comMake visitor the responsible for choosing traversal strategy* This changes the mode that traversal is chosen. Now it can be completely customized by the user when providing a visitor.
* It is backwards compatible. That is, previous algorithms conserve the same default traversal strategies as befo...* This changes the mode that traversal is chosen. Now it can be completely customized by the user when providing a visitor.
* It is backwards compatible. That is, previous algorithms conserve the same default traversal strategies as before.
Closes #4https://gitlab.dune-project.org/staging/dune-typetree/-/merge_requests/68[WIP] Add 'fluent interface' for visitor construction2021-02-11T22:14:37ZCarsten Gräsergraeser@math.fau.de[WIP] Add 'fluent interface' for visitor constructionFollowing an idea originally proposed by @smuething long time ago
this allows to create a visitor using lambda expressions.
In contrast to providing plain callbacks to a global
traversal function (as in `forEachNode()`) this has some ben...Following an idea originally proposed by @smuething long time ago
this allows to create a visitor using lambda expressions.
In contrast to providing plain callbacks to a global
traversal function (as in `forEachNode()`) this has some benefits:
* It simplifies the `Visitor` approach instead of creating
a new traversal mechanism. Hence you still have the full
flexibility of the `Visitor` approach.
* Instead of positional arguments you have named arguments
which is far less error prone.
* You can use the existing mechanism to switch traversal types.
* You can easily extend existing visitors.
* You can chain several callbacks for a single purpose (e.g. pre(...)).
As far as I remember this design pattern is called 'fluent design'.
Here we use the piping syntax which was popularized by range
adaptors from C++20 (and its prototype in range-V3). Usage example:
```cpp
int counter = 0;
applyToTree(tree, makeVisitor() // create default doing nothig
| pre([&](auto&&...) { ++counter; }) // extend by pre callback
| leaf([&](auto&&...) { ++counter; }) // extend by leaf callback
); // traverse tree and count all nodes
```https://gitlab.dune-project.org/staging/dune-typetree/-/merge_requests/39WIP: Feature/simple treetransformation2020-12-07T09:38:45ZCarsten Gräsergraeser@math.fau.deWIP: Feature/simple treetransformationThis demonstrates how to implement tree transformation manually with
the help of some small utilities. For example the transformation
in testtypetreetransformation.cc can be written as
```cpp
struct GenericBasedTransformation
{
auto o...This demonstrates how to implement tree transformation manually with
the help of some small utilities. For example the transformation
in testtypetreetransformation.cc can be written as
```cpp
struct GenericBasedTransformation
{
auto operator()(const SimpleLeaf& node) {
return TargetLeaf(node, *this);
}
template<class Node,
std::enable_if_t<hasImplementationTag<Node, SimplePowerTag>(), int> = 0>
auto operator()(const Node& node) {
return Dune::TypeTree::genericPowerNodeTransformation<TargetPower>(node, *this);
}
template<class Node,
std::enable_if_t<hasImplementationTag<Node, SimpleCompositeTag>(), int> = 0>
auto operator()(const Node& node) {
return Dune::TypeTree::genericCompositeNodeTransformation<TargetComposite>(node, *this);
}
};
```
This will do the same as the current mechanism together with the declaration
```cpp
struct TestTransformation {};
// register leaf node
template<typename SL>
Dune::TypeTree::GenericLeafNodeTransformation<SimpleLeaf,TestTransformation,TargetLeaf>
registerNodeTransformation(SL* sl, TestTransformation* t, SimpleLeafTag* tag);
template<typename SP>
Dune::TypeTree::GenericPowerNodeTransformation<SP,TestTransformation,TargetPower>
registerNodeTransformation(SP* sp, TestTransformation* t, SimplePowerTag* tag);
template<typename SC>
Dune::TypeTree::GenericCompositeNodeTransformation<SC,TestTransformation,TargetComposite>
registerNodeTransformation(SC* sc, TestTransformation* t, SimpleCompositeTag* tag);
```
Notice that it's comparably short but has certain advantages:
* More readable, easier to understand because you directly see what's happening.
That's not quite the case for the declarative style to define transformations.
* Easily customizable. Since you write the transformation directly instead
of a declaration hooking into some abstract mechanism, you can easily adjust
parts of the code to your needs. E.g. instead of hard-wiring the customization
by tags into the interface you can switch overloads using whatever condition
you want.
* Don't clutter the namespace by 'registering' transformation declarations.
Have a look at testtypetreetransformation.cc for the example. Notice that this
does nor propose an interface change but more a different convention.
This relies on core/dune-common!495.