AI 24/25 Project Software
Documentation for the AI 24/25 course programming project software
Loading...
Searching...
No Matches
merge_tree.h
1#ifndef MERGE_AND_SHRINK_MERGE_TREE_H
2#define MERGE_AND_SHRINK_MERGE_TREE_H
3
4#include <memory>
5#include <utility>
6
7namespace utils {
8class LogProxy;
9class RandomNumberGenerator;
10}
11
12namespace merge_and_shrink {
13extern const int UNINITIALIZED;
14
15/*
16 Binary tree data structure with convenience methods for removing
17 sibling leaf nodes and modifying the tree by removing specific
18 leaf nodes that are not siblings (see also MergeTree class).
19 */
20struct MergeTreeNode {
21 MergeTreeNode *parent;
22 MergeTreeNode *left_child;
23 MergeTreeNode *right_child;
24 int ts_index;
25
26 MergeTreeNode() = delete;
27 // Copy constructor. Does not set parent pointers.
28 MergeTreeNode(const MergeTreeNode &other);
29 MergeTreeNode(int ts_index);
30 MergeTreeNode(MergeTreeNode *left_child, MergeTreeNode *right_child);
31 ~MergeTreeNode();
32
33 MergeTreeNode *get_left_most_sibling();
34 std::pair<int, int> erase_children_and_set_index(int new_index);
35 // Find the parent node for the given index.
36 MergeTreeNode *get_parent_of_ts_index(int index);
37 int compute_num_internal_nodes() const;
38 void inorder(int offset, int current_indentation, utils::LogProxy &log) const;
39
40 bool is_leaf() const {
41 return !left_child && !right_child;
42 }
43
44 bool has_two_leaf_children() const {
45 return left_child && right_child &&
46 left_child->is_leaf() && right_child->is_leaf();
47 }
48};
49
50enum class UpdateOption {
51 USE_FIRST,
52 USE_SECOND,
53 USE_RANDOM
54};
55
56/*
57 This class manages a binary tree data structure (MergeTreeNode) that
58 represents a merge tree.
59
60 In the common use case, the merge tree is used as "the merge strategy"
61 and hence it is always synchronized with the current factored transition
62 system managed by the merge-and-shrink heuristic. In that case, when asked
63 for a next merge, the *left-most* sibling leaf pair is returned and their
64 parent node updated to represent the resulting composite transition system.
65
66 NOTE: returning the left-most sibling leaf pair does not allow to represent
67 arbitrary merge strategies with this class, because there is no possibility
68 to specify the merge order of current sibling leaf nodes in an arbitrary
69 way. For existing precomputed merge strategies like the linear ones or MIASM,
70 this does not matter.
71
72 For the less common use case of using a merge tree within another merge
73 strategy where the merge tree acts as a fallback mechanism, the merge tree
74 has to be kept synchronized with the factored transition system. This
75 requires informing the merge tree about all merges that happen and that may
76 differ from what the merge tree prescribes. The method update provides this
77 functionality, using the user specified choice update_option to choose one
78 of two possible leaf nodes representing the indices of the given merge as the
79 future node representing the merge.
80*/
81class MergeTree {
82 MergeTreeNode *root;
83 std::shared_ptr<utils::RandomNumberGenerator> rng;
84 UpdateOption update_option;
85 /*
86 Find the two parents (can be the same) of the given indices. The first
87 one will correspond to a merge that would have been merged earlier in
88 the merge tree than the second one.
89 */
90 std::pair<MergeTreeNode *, MergeTreeNode *> get_parents_of_ts_indices(
91 const std::pair<int, int> &ts_indices, int new_index);
92 MergeTree() = delete;
93public:
94 MergeTree(
95 MergeTreeNode *root,
96 const std::shared_ptr<utils::RandomNumberGenerator> &rng,
97 UpdateOption update_option);
98 ~MergeTree();
99 std::pair<int, int> get_next_merge(int new_index);
100 /*
101 Inform the merge tree about a merge that happened independently of
102 using the tree's method get_next_merge.
103 */
104 void update(std::pair<int, int> merge, int new_index);
105
106 bool done() const {
107 return root->is_leaf();
108 }
109
110 int compute_num_internal_nodes() const {
111 return root->compute_num_internal_nodes();
112 }
113
114 // NOTE: this performs the "inverted" inorder_traversal, i.e. from right
115 // to left, so that the printed tree matches the correct left-to-right
116 // order.
117 void inorder_traversal(int indentation_offset, utils::LogProxy &log) const;
118};
119}
120
121#endif