111# ifndef TREE_DECOMPOSITION_H
112# define TREE_DECOMPOSITION_H
120# include <type_traits>
134 namespace tree_decomposition_detail
153 template <AlephGraph GT, ArcFilter<GT> SA>
160 static constexpr size_t NONE = std::numeric_limits<size_t>::max();
180 return std::make_pair(u, v);
186 <<
where <<
": id=" <<
id <<
" is out of range [0, " <<
n_ <<
")";
196 <<
"Rooted_Tree_Topology: root node provided but graph is empty";
208 Node *p = it.get_curr();
215 <<
"Rooted_Tree_Topology: failed to index all graph nodes";
217 if (
root_ ==
nullptr)
221 <<
"Rooted_Tree_Topology: root node does not belong to graph";
233 for (
size_t i = 0; i <
n_; ++i)
241 Arc *a = it.get_curr_ne();
249 <<
"Rooted_Tree_Topology: arc endpoint is not indexed";
255 <<
"Rooted_Tree_Topology: self-loop detected in filtered graph";
259 <<
"Rooted_Tree_Topology: parallel/duplicate edge detected in filtered graph";
266 <<
"Rooted_Tree_Topology: filtered graph is not a tree (expected "
270 it.has_curr(); it.next_ne())
272 const auto & [
fst,
snd] = it.get_curr();
275 const size_t u =
fst.first;
276 const size_t v =
fst.second;
288 for (
size_t i = 0; i <
n_; ++i)
305 auto &
fr = stack.
top();
314 if (
nxt ==
fr.parent)
318 <<
"Rooted_Tree_Topology: filtered graph is not acyclic";
326 <<
"Rooted_Tree_Topology: filtered graph is not connected";
356 <<
"Rooted_Tree_Topology::id_of: null node";
360 <<
"Rooted_Tree_Topology::id_of: node does not belong to graph";
367 check_id(
id,
"Rooted_Tree_Topology::node_of");
393 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
421 const size_t n =
size();
433 for (
size_t i = 0; i < n; ++i)
445 for (
size_t i = 0; i < n; ++i)
471 auto &
fr = stack.
top();
480 if (
nxt ==
fr.parent)
484 <<
"Gen_Heavy_Light_Decomposition: filtered graph is not acyclic";
497 <<
"Gen_Heavy_Light_Decomposition: filtered graph is not connected";
499 for (
size_t i = order.
size(); i-- > 0;)
501 const size_t u = order(i);
528 head_(u) = chain_head;
542 <<
"Gen_Heavy_Light_Decomposition: invalid decomposition size";
553 : topology_(g,
root,
std::move(sa))
555 build_decomposition();
564 : topology_(g, nullptr,
std::move(sa))
566 build_decomposition();
577 return topology_.node_of(
id);
582 return topology_.id_of(node);
587 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::parent_id");
593 const size_t pid = parent_id(id_of(node));
594 return pid == NONE ? nullptr : node_of(pid);
599 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::depth_of_id");
605 return depth_of_id(id_of(node));
610 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::subtree_size_of_id");
611 return subtree_size_(
id);
616 return subtree_size_of_id(id_of(node));
621 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::heavy_child_id");
627 const size_t cid = heavy_child_id(id_of(node));
628 return cid == NONE ? nullptr : node_of(
cid);
633 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::head_id");
639 return node_of(head_id(id_of(node)));
644 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::position_of_id");
650 return position_of_id(id_of(node));
656 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::subtree_range_id");
657 const size_t l = pos_(
id);
658 const size_t r =
l + subtree_size_(
id) - 1;
665 return subtree_range_id(id_of(node));
671 const Range r = subtree_range_id(u);
672 const size_t pv = position_of_id(v);
679 return is_ancestor_id(id_of(u), id_of(v));
685 ensure_not_empty(
"Gen_Heavy_Light_Decomposition::lca_id");
686 topology_.validate_id(u,
"Gen_Heavy_Light_Decomposition::lca_id");
687 topology_.validate_id(v,
"Gen_Heavy_Light_Decomposition::lca_id");
689 while (head_(u) != head_(v))
690 if (depth_(head_(u)) >= depth_(head_(v)))
691 u = parent_(head_(u));
693 v = parent_(head_(v));
695 return (depth_(u) <= depth_(v)) ? u : v;
701 return node_of(lca_id(id_of(u), id_of(v)));
707 const size_t a = lca_id(u, v);
708 return depth_(u) + depth_(v) - 2 * depth_(a);
714 return distance_id(id_of(u), id_of(v));
730 ensure_not_empty(
"Gen_Heavy_Light_Decomposition::for_each_path_segment_id");
731 topology_.validate_id(u,
"Gen_Heavy_Light_Decomposition::for_each_path_segment_id");
732 topology_.validate_id(v,
"Gen_Heavy_Light_Decomposition::for_each_path_segment_id");
736 while (head_(u) != head_(v))
737 if (depth_(head_(u)) >= depth_(head_(v)))
739 visit(pos_(head_(u)), pos_(u),
true);
740 u = parent_(head_(u));
745 v = parent_(head_(v));
748 if (depth_(u) >= depth_(v))
749 visit(pos_(v), pos_(u),
true);
756 visit(left, right,
false);
764 for_each_path_segment_id(id_of(u), id_of(v), std::forward<F>(
visit));
776 for_each_path_segment_id(u, v,
777 [&](
const size_t l,
const size_t r,
const bool)
809 template <AlephGraph
GT,
829 template <
class Getter>
830 requires std::invocable<Getter, Node *>
and
831 std::convertible_to<std::invoke_result_t<Getter, Node *>,
T>
835 const size_t n =
hld.size();
840 for (
size_t id = 0;
id < n; ++id)
842 const size_t p =
hld.position_of_id(
id);
843 base(p) =
static_cast<T>(
getter(
hld.node_of(
id)));
854 return static_cast<T>(p->get_info());
887 template <
class Getter>
888 requires std::invocable<Getter, Node *>
and
889 std::convertible_to<std::invoke_result_t<Getter, Node *>,
T>
905 template <
class Getter>
906 requires std::invocable<Getter, Node *>
and
907 std::convertible_to<std::invoke_result_t<Getter, Node *>,
T>
935 hld_.for_each_path_segment_id(u, v,
955 const auto range =
hld_.subtree_range_id(
id);
1024 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
1057 const size_t n =
size();
1066 for (
size_t i = 0; i < n; ++i)
1090 const size_t u = stack.
pop();
1114 <<
"Gen_Centroid_Decomposition: empty component while choosing centroid";
1116 for (
size_t i =
total; i-- > 0;)
1118 const size_t u =
nodes(i);
1132 size_t centroid =
nodes(0);
1135 for (
size_t i = 0; i <
total; ++i)
1137 const size_t u =
nodes(i);
1174 const Frame
fr = stack.
pop();
1184 stack.
push({v,
fr.node,
fr.dist + 1});
1191 const size_t n =
size();
1230 tasks.
push({v, centroid,
task.level + 1});
1234 <<
"Gen_Centroid_Decomposition: invalid centroid tree size";
1240 : topology_(g,
root,
std::move(sa))
1242 build_centroid_tree();
1247 : topology_(g, nullptr,
std::move(sa))
1249 build_centroid_tree();
1260 return topology_.node_of(
id);
1265 return topology_.id_of(node);
1271 return centroid_root_;
1277 return centroid_root_ == NONE ? nullptr : node_of(centroid_root_);
1283 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_parent_id");
1284 return centroid_parent_(
id);
1290 const size_t pid = centroid_parent_id(id_of(node));
1291 return pid == NONE ? nullptr : node_of(pid);
1297 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_level_of_id");
1298 return centroid_level_(
id);
1304 return centroid_level_of_id(id_of(node));
1311 for (
size_t i = 0; i <
size(); ++i)
1312 ret = std::max(
ret, centroid_level_(i));
1319 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_path_length_of_id");
1320 return centroid_ancestors_(
id).size();
1326 return centroid_path_length_of_id(id_of(node));
1332 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_ancestors_of_id");
1333 return centroid_ancestors_(
id);
1339 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_distances_of_id");
1340 return centroid_distances_(
id);
1346 return centroid_ancestors_of_id(id_of(node));
1352 return centroid_distances_of_id(id_of(node));
1357 const size_t node)
const
1359 topology_.validate_id(
ancestor,
"Gen_Centroid_Decomposition::is_centroid_ancestor_id");
1360 topology_.validate_id(node,
"Gen_Centroid_Decomposition::is_centroid_ancestor_id");
1362 const auto &
chain = centroid_ancestors_(node);
1363 for (
size_t i = 0; i <
chain.size(); ++i)
1375 const size_t centroid)
const
1377 topology_.validate_id(node,
"Gen_Centroid_Decomposition::distance_to_centroid_id");
1378 topology_.validate_id(centroid,
"Gen_Centroid_Decomposition::distance_to_centroid_id");
1380 const auto &
chain = centroid_ancestors_(node);
1381 const auto &
dists = centroid_distances_(node);
1383 for (
size_t i = 0; i <
chain.size(); ++i)
1384 if (
chain(i) == centroid)
1397 ensure_not_empty(
"Gen_Centroid_Decomposition::for_each_centroid_ancestor_id");
1398 topology_.validate_id(node,
"Gen_Centroid_Decomposition::for_each_centroid_ancestor_id");
1400 const auto &
chain = centroid_ancestors_(node);
1401 const auto &
dists = centroid_distances_(node);
1404 <<
"Gen_Centroid_Decomposition: invalid centroid annotation state";
1406 for (
size_t i = 0; i <
chain.size(); ++i)
1417 for_each_centroid_ancestor_id(id_of(node), std::forward<F>(f));
1423 template <
class GT,
class SA = Dft_Show_Arc<GT>>
1434 template <
class GT,
class SA = Dft_Show_Arc<GT>>
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
C++20 concepts for the protocol shared by graph algorithms.
Standard functor implementations and comparison objects.
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
size_t size_t int32_t value
Simple dynamic array with automatic resizing and functional operations.
static Array create(size_t n)
Create an array with n logical elements.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Dynamic stack of elements of generic type T based on a singly linked list.
T & top()
Return a modifiable reference to the top item of the stack.
bool is_empty() const noexcept
Check if the stack is empty.
T pop()
Remove and return the top item of the stack.
T & push(const T &data)
Push an item by copy onto the top of the stack.
Generic key-value map implemented on top of a binary search tree.
typename Base::Iterator Iterator
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Centroid decomposition over a rooted tree represented as an Aleph graph.
Node * centroid_parent(const Node *node) const
Parent centroid of node (or nullptr if centroid root).
size_t centroid_path_length_of(const Node *node) const
Number of centroid ancestors stored for node.
Array< size_t > centroid_parent_
Array< size_t > centroid_level_
Array< Array< size_t > > centroid_distances_
bool is_empty() const noexcept
size_t centroid_level_of_id(const size_t id) const
Level of centroid id in centroid tree (root level = 0).
void build_centroid_tree()
const Array< size_t > & centroid_ancestors_of(const Node *node) const
Centroid ancestors of node from centroid root down to local centroid.
Node * centroid_root() const noexcept
Root centroid node of the centroid tree (or nullptr if empty).
bool is_centroid_ancestor_id(const size_t ancestor, const size_t node) const
True iff ancestor is in the centroid-ancestor chain of node.
void ensure_not_empty(const char *where) const
size_t centroid_level_of(const Node *node) const
Level of centroid node in centroid tree (root level = 0).
size_t centroid_root_id() const noexcept
Root centroid ID of the centroid tree (or NONE if empty).
Gen_Centroid_Decomposition(const GT &g, Node *root, SA sa=SA())
Construct using an explicit root node.
const Array< size_t > & centroid_ancestors_of_id(const size_t id) const
Centroid ancestors of node ID from centroid root down to local centroid.
Node * node_of(const size_t id) const
Array< size_t > local_subtree_
size_t centroid_parent_id(const size_t id) const
Parent centroid ID of id (or NONE if centroid root).
size_t centroid_path_length_of_id(const size_t id) const
Number of centroid ancestors stored for node ID.
const Array< size_t > & centroid_distances_of(const Node *node) const
Distances to centroid ancestors (aligned with centroid_ancestors_of).
size_t max_centroid_level() const noexcept
Maximum centroid-tree level.
size_t distance_to_centroid_id(const size_t node, const size_t centroid) const
Distance from node ID to a centroid ancestor ID.
Node * root() const noexcept
Array< size_t > local_parent_
void append_centroid_annotations(const size_t centroid)
static constexpr size_t NONE
void for_each_centroid_ancestor_id(const size_t node, F &&f) const
Visit each centroid ancestor of node ID.
size_t id_of(const Node *node) const
Array< size_t > collect_component_nodes(const size_t start)
void for_each_centroid_ancestor(const Node *node, F &&f) const
Visit each centroid ancestor of node.
const Array< size_t > & centroid_distances_of_id(const size_t id) const
Distances to centroid ancestors (aligned with centroid_ancestors_of_id).
Gen_Centroid_Decomposition(const GT &g, SA sa=SA())
Construct using the first graph node as root.
size_t size() const noexcept
size_t choose_centroid(const Array< size_t > &nodes)
Array< Array< size_t > > centroid_ancestors_
size_t root_id() const noexcept
Segment-tree-powered path/subtree queries over an HLD layout.
Gen_Heavy_Light_Decomposition< GT, SA > hld_
T query_subtree(const Node *node) const
Subtree query for node in O(log n).
static Array< T > build_base_from_node_info(const Gen_Heavy_Light_Decomposition< GT, SA > &hld)
void set_node(const Node *node, const T &value)
Point assignment: a[node] = value.
T query_path(const Node *u, const Node *v) const
Path query between two nodes in O(log^2 n).
void update_node(const Node *node, const T &delta)
Point update: a[node] = Op(a[node], delta).
Gen_HLD_Path_Query(const GT &g, Node *root, const T &identity, Op op=Op(), SA sa=SA())
Construct from graph/root using node->get_info() as initial values.
void ensure_not_empty(const char *where) const
const Gen_Heavy_Light_Decomposition< GT, SA > & decomposition() const noexcept
T query_path_id(const size_t u, const size_t v) const
Path query between two node IDs in O(log^2 n).
Gen_HLD_Path_Query(const GT &g, const T &identity, Op op=Op(), SA sa=SA())
Construct from graph (first node as root) using node->get_info().
T get_node_id(const size_t id) const
Return current value at node ID.
size_t size() const noexcept
T query_subtree_id(const size_t id) const
Subtree query for node ID in O(log n).
void update_node_id(const size_t id, const T &delta)
Point update: a[id] = Op(a[id], delta).
bool is_empty() const noexcept
void set_node_id(const size_t id, const T &value)
Point assignment: a[id] = value.
Gen_Segment_Tree< T, Op > segment_tree_
and static std::convertible_to< std::invoke_result_t< Getter, Node * >, T > Array< T > build_base_array(const Gen_Heavy_Light_Decomposition< GT, SA > &hld, Getter getter)
and std::convertible_to< std::invoke_result_t< Getter, Node * >, T > Gen_HLD_Path_Query(const GT &g, Node *root, Getter getter, const T &identity, Op op=Op(), SA sa=SA())
Construct with custom node-to-value getter.
and std::convertible_to< std::invoke_result_t< Getter, Node * >, T > Gen_HLD_Path_Query(const GT &g, Getter getter, const T &identity, Op op=Op(), SA sa=SA())
Construct with custom getter and implicit root (first node).
T get_node(const Node *node) const
Return current value at node.
Heavy-Light Decomposition over a rooted tree represented as an Aleph graph.
Gen_Heavy_Light_Decomposition(const GT &g, SA sa=SA())
Construct using the first graph node as root.
size_t position_of(const Node *node) const
static constexpr size_t NONE
void for_each_path_segment_id(size_t u, size_t v, F &&visit) const
Enumerate path segments from u to v in path order.
Array< size_t > subtree_size_
size_t parent_id(const size_t id) const
size_t root_id() const noexcept
size_t head_id(const size_t id) const
size_t distance_id(const size_t u, const size_t v) const
Distance (number of edges) between two node IDs.
size_t lca_id(size_t u, size_t v) const
Lowest common ancestor in O(log n).
size_t position_of_id(const size_t id) const
Node * head_of(const Node *node) const
size_t distance(const Node *u, const Node *v) const
Distance (number of edges) between two nodes.
size_t subtree_size_of_id(const size_t id) const
size_t depth_of_id(const size_t id) const
size_t heavy_child_id(const size_t id) const
void ensure_not_empty(const char *where) const
Node * lca(const Node *u, const Node *v) const
Lowest common ancestor in O(log n).
Node * heavy_child(const Node *node) const
bool is_ancestor(const Node *u, const Node *v) const
True iff u is ancestor of v in the rooted tree.
Range subtree_range(const Node *node) const
Base-array range of a full subtree (inclusive endpoints).
size_t id_of(const Node *node) const
size_t depth_of(const Node *node) const
Gen_Heavy_Light_Decomposition(const GT &g, Node *root, SA sa=SA())
Construct using an explicit root node.
Node * node_of(const size_t id) const
size_t subtree_size_of(const Node *node) const
Range subtree_range_id(const size_t id) const
Base-array range of a full subtree (inclusive endpoints).
Node * parent_of(const Node *node) const
Node * root() const noexcept
bool is_ancestor_id(const size_t u, const size_t v) const
True iff u is ancestor of v in the rooted tree.
void for_each_path_segment(const Node *u, const Node *v, F &&visit) const
Enumerate path segments from u to v in path order.
void for_each_path_segment_undirected_id(const size_t u, const size_t v, F &&visit) const
Enumerate path segments ignoring direction.
void build_decomposition()
size_t size() const noexcept
bool is_empty() const noexcept
Segment tree over an arbitrary associative binary operation.
typename Node::Node_Type Node_Type
The arc class type.
Graph_Node< Node_Info > Node
The graph type.
Graph_Arc< Arc_Info > Arc
The node class type.
Filtered iterator on the nodes of a graph.
Node * node_of(const size_t id) const
bool is_empty() const noexcept
void validate_id(const size_t id, const char *where) const
MapOLhash< Node *, size_t > node_to_id_
std::pair< size_t, size_t > Pair_Key
const Array< Node * > & id_to_node() const noexcept
void build_simple_adjacency()
void validate_connected_acyclic() const
size_t root_id() const noexcept
Rooted_Tree_Topology(const GT &g, Node *root, SA sa=SA())
static constexpr size_t NONE
size_t size() const noexcept
size_t id_of(const Node *node) const
Node * root() const noexcept
Array< Array< size_t > > adjacency_
const Array< Array< size_t > > & adjacency() const noexcept
Array< Node * > id_to_node_
void check_id(const size_t id, const char *where) const
static Pair_Key normalize_pair(size_t u, size_t v) noexcept
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
DynArray< Graph::Node * > nodes
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Main namespace for Aleph-w library functions.
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Container< T > range(const T start, const T end, const T step=1)
Generate a range of values [start, end] with a given step.
Filtered iterator on all the arcs of a graph.
Default filter for filtered iterators on arcs.
Open addressing hash map using linear probing.
Data & find(const Key &key)
Find and return the value for a key.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair (copy semantics).
Pair * search(const Key &key) const noexcept
Search for a key in the map.
Task with priority for job scheduling.
Dynamic array container with automatic resizing.
Dynamic stack implementation based on linked lists.
Dynamic map with open hashing.
Dynamic key-value map based on balanced binary search trees.
Generic graph and digraph implementations.
Segment trees for dynamic range queries with lazy propagation.