File: supertree_enumerator.hpp

package info (click to toggle)
iqtree 2.0.7%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,700 kB
  • sloc: cpp: 142,571; ansic: 57,789; sh: 275; python: 242; makefile: 95
file content (173 lines) | stat: -rw-r--r-- 5,839 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#ifndef SUPERTREE_ENUMERATOR_HPP
#define SUPERTREE_ENUMERATOR_HPP

#include "bipartitions.hpp"
#include "stack_allocator.hpp"
#include "union_find.hpp"

#include "supertree_helpers.hpp"
#include "utils.hpp"

namespace terraces {

template <typename Callback>
class tree_enumerator {
	using result_type = typename Callback::result_type;

private:
	Callback m_cb;

	utils::free_list m_fl1;
	utils::free_list m_fl2;
	utils::free_list m_fl3;
	index m_fl1_allocsize;
	index m_fl2_allocsize;
	index m_fl3_allocsize;

	const constraints* m_constraints;

	result_type run(const ranked_bitvector& leaves, const bitvector& constraint_occ);
	result_type iterate(bipartitions& bip_it, const bitvector& new_constraint_occ);

	void init_freelists(index leaf_count, index constraint_count);
	utils::stack_allocator<index> leaf_allocator();
	utils::stack_allocator<index> c_occ_allocator();
	utils::stack_allocator<index> union_find_allocator();

public:
	explicit tree_enumerator(Callback cb);
	result_type run(index num_leaves, const constraints& constraints,
	                const std::vector<bool>& root_split);
	result_type run(index num_leaves, const constraints& constraints, index root_leaf);
	result_type run(index num_leaves, const constraints& constraints);
	const Callback& callback() const { return m_cb; }
};

template <typename Callback>
tree_enumerator<Callback>::tree_enumerator(Callback cb)
        : m_cb{std::move(cb)}, m_constraints{nullptr} {}

template <typename Callback>
auto tree_enumerator<Callback>::run(index num_leaves, const constraints& constraints)
        -> result_type {
	init_freelists(num_leaves, constraints.size());
	auto leaves = full_ranked_set(num_leaves, leaf_allocator());
	auto c_occ = full_set(constraints.size(), c_occ_allocator());
	assert(filter_constraints(leaves, c_occ, constraints, c_occ_allocator()) == c_occ);
	m_constraints = &constraints;
	return run(leaves, c_occ);
}

template <typename Callback>
auto tree_enumerator<Callback>::run(index num_leaves, const constraints& constraints,
                                    const std::vector<bool>& root_split) -> result_type {
	init_freelists(num_leaves, constraints.size());
	auto leaves = full_ranked_set(num_leaves, leaf_allocator());
	auto c_occ = full_set(constraints.size(), c_occ_allocator());
	assert(filter_constraints(leaves, c_occ, constraints, c_occ_allocator()) == c_occ);
	assert(root_split.size() == num_leaves);
	// enter the call
	m_cb.enter(leaves);
	// no base cases
	assert(num_leaves > 2);
	// assert(!constraints.empty()); is not necessary, since is returns correct values anyway
	// build bipartition iterator:
	auto sets = union_find::make_bipartition(root_split, union_find_allocator());
	m_constraints = &constraints;
	auto bip_it = bipartitions{leaves, sets, leaf_allocator()};
	return m_cb.exit(iterate(bip_it, c_occ));
}

template <typename Callback>
auto tree_enumerator<Callback>::run(index num_leaves, const constraints& constraints,
                                    index root_leaf) -> result_type {
	std::vector<bool> root_split(num_leaves);
	root_split[root_leaf] = true;
	return run(num_leaves, constraints, root_split);
}

template <typename Callback>
auto tree_enumerator<Callback>::run(const ranked_bitvector& leaves, const bitvector& constraint_occ)
        -> result_type {
	m_cb.enter(leaves);

	// base cases: only a few leaves
	assert(leaves.count() > 0);
	if (leaves.count() == 1) {
		return m_cb.exit(m_cb.base_one_leaf(leaves.first_set()));
	}

	if (leaves.count() == 2) {
		auto fst = leaves.first_set();
		auto snd = leaves.next_set(fst);
		return m_cb.exit(m_cb.base_two_leaves(fst, snd));
	}

	bitvector new_constraint_occ =
	        filter_constraints(leaves, constraint_occ, *m_constraints, c_occ_allocator());
	// base case: no constraints left
	if (new_constraint_occ.empty()) {
		return m_cb.exit(m_cb.base_unconstrained(leaves));
	}

	union_find sets = apply_constraints(leaves, new_constraint_occ, *m_constraints,
	                                    union_find_allocator());
	bipartitions bip_it(leaves, sets, leaf_allocator());

	return m_cb.exit(iterate(bip_it, new_constraint_occ));
}

template <typename Callback>
void tree_enumerator<Callback>::init_freelists(index leaf_count, index constraint_count) {
	m_fl1_allocsize = ranked_bitvector::alloc_size(leaf_count);
	m_fl2_allocsize = ranked_bitvector::alloc_size(constraint_count);
	m_fl3_allocsize = leaf_count;
	m_fl1 = {};
	m_fl2 = {};
	m_fl3 = {};
}

template <typename Callback>
utils::stack_allocator<index> tree_enumerator<Callback>::leaf_allocator() {
	return {m_fl1, m_fl1_allocsize};
}

template <typename Callback>
utils::stack_allocator<index> tree_enumerator<Callback>::c_occ_allocator() {
	return {m_fl2, m_fl2_allocsize};
}

template <typename Callback>
utils::stack_allocator<index> tree_enumerator<Callback>::union_find_allocator() {
	return {m_fl3, m_fl3_allocsize};
}

template <typename Callback>
auto tree_enumerator<Callback>::iterate(bipartitions& bip_it, const bitvector& new_constraint_occ)
        -> result_type {
	if (m_cb.fast_return(bip_it)) {
		return m_cb.fast_return_value(bip_it);
	}

	auto result = m_cb.begin_iteration(bip_it, new_constraint_occ, *m_constraints);
	// iterate over all possible bipartitions
	for (auto bip = bip_it.begin_bip();
	     bip < bip_it.end_bip() && m_cb.continue_iteration(result); ++bip) {
		m_cb.step_iteration(bip_it, bip);
		auto set = bip_it.get_first_set(bip, leaf_allocator());
		m_cb.left_subcall();
		auto left_result = run(set, new_constraint_occ);
		bip_it.flip_set(set);
		m_cb.right_subcall();
		auto right_result = run(set, new_constraint_occ);
		// accumulate result
		result = m_cb.accumulate(result, m_cb.combine(left_result, right_result));
	}
	m_cb.finish_iteration();

	return result;
}

} // namespace terraces

#endif // SUPERTREE_ENUMERATOR_HPP