5#ifndef BITCOIN_CLUSTER_LINEARIZE_H
6#define BITCOIN_CLUSTER_LINEARIZE_H
29template<
typename SetType>
61 if (a.m_used != b.m_used)
return false;
63 for (
auto idx : a.m_used) {
64 if (a.entries[idx] != b.entries[idx])
return false;
93 Assume(mapping.size() == depgraph.PositionRange());
94 Assume((pos_range == 0) == (depgraph.TxCount() == 0));
96 auto new_idx = mapping[i];
97 Assume(new_idx < pos_range);
99 entries[new_idx].ancestors = SetType::Singleton(new_idx);
100 entries[new_idx].descendants = SetType::Singleton(new_idx);
103 entries[new_idx].feerate = depgraph.entries[i].feerate;
108 for (
auto j : depgraph.GetReducedParents(i)) parents.Set(mapping[j]);
137 static constexpr auto ALL_POSITIONS = SetType::Fill(SetType::Size());
138 auto available = ALL_POSITIONS -
m_used;
141 if (new_idx ==
entries.size()) {
142 entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
144 entries[new_idx] =
Entry(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
170 entry.ancestors &=
m_used;
171 entry.descendants &=
m_used;
185 for (
auto par : parents -
Ancestors(child)) {
190 if (par_anc.None())
return;
192 const auto& chl_des =
entries[child].descendants;
193 for (
auto anc_of_par : par_anc) {
194 entries[anc_of_par].descendants |= chl_des;
198 entries[dec_of_chl].ancestors |= par_anc;
214 for (
auto parent : parents) {
215 if (parents[parent]) {
235 for (
auto child : children) {
236 if (children[child]) {
251 for (
auto pos : elems)
ret +=
entries[pos].feerate;
269 auto to_add = SetType::Singleton(tx);
273 for (
auto add : to_add) {
279 }
while (to_add.Any());
292 if (todo.None())
return todo;
315 void AppendTopo(std::vector<DepGraphIndex>& list,
const SetType& select)
const noexcept
318 for (
auto i : select) list.push_back(i);
320 const auto a_anc_count = entries[a].ancestors.Count();
321 const auto b_anc_count = entries[b].ancestors.Count();
322 if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count;
360template<
typename SetType>
387 feerate += depgraph.FeeRate(pos);
418 swap(a.transactions, b.transactions);
419 swap(a.feerate, b.feerate);
427template<
typename SetType>
430 std::vector<SetInfo<SetType>>
ret;
435 while (!
ret.empty() && new_chunk.
feerate >>
ret.back().feerate) {
436 new_chunk |=
ret.back();
440 ret.emplace_back(std::move(new_chunk));
447template<
typename SetType>
450 std::vector<FeeFrac>
ret;
453 auto new_chunk = depgraph.FeeRate(i);
455 while (!
ret.empty() && new_chunk >>
ret.back()) {
456 new_chunk +=
ret.back();
460 ret.push_back(std::move(new_chunk));
466template<
typename F,
typename Arg>
468 std::regular_invocable<F, Arg, Arg> &&
469 std::is_same_v<std::invoke_result_t<F, Arg, Arg>, std::strong_ordering>;
641template<
typename SetType>
709 for (
auto tx_idx : tx_idxs) {
710 if (pos == 0)
return tx_idx;
722 template<
bool Subtract>
726 for (
auto tx_idx : chunk) {
729 tx_data.chunk_rep = chunk_rep;
732 auto child_deps = std::span{tx_data.child_deps};
733 for (
auto dep_idx : child_deps) {
735 Assume(dep_entry.parent == tx_idx);
737 if (!dep_entry.active)
continue;
740 if (dep_entry.top_setinfo.transactions[query]) {
741 if constexpr (Subtract) {
742 dep_entry.top_setinfo -= dep_change;
744 dep_entry.top_setinfo |= dep_change;
756 auto& child_tx_data =
m_tx_data[dep_data.child];
757 auto& parent_tx_data =
m_tx_data[dep_data.parent];
760 Assume(parent_tx_data.chunk_rep != child_tx_data.chunk_rep);
761 auto& par_chunk_data =
m_tx_data[parent_tx_data.chunk_rep];
762 auto& chl_chunk_data =
m_tx_data[child_tx_data.chunk_rep];
763 TxIdx top_rep = parent_tx_data.chunk_rep;
764 auto top_part = par_chunk_data.chunk_setinfo;
765 auto bottom_part = chl_chunk_data.chunk_setinfo;
767 par_chunk_data.chunk_setinfo |= bottom_part;
768 m_cost += par_chunk_data.chunk_setinfo.transactions.Count();
789 UpdateChunk<false>(top_part.transactions, dep_data.parent,
790 top_rep, bottom_part);
795 UpdateChunk<false>(bottom_part.transactions, dep_data.child,
798 dep_data.active =
true;
799 dep_data.top_setinfo = top_part;
808 auto& parent_tx_data =
m_tx_data[dep_data.parent];
810 dep_data.active =
false;
812 auto& chunk_data =
m_tx_data[parent_tx_data.chunk_rep];
813 m_cost += chunk_data.chunk_setinfo.transactions.Count();
814 auto top_part = dep_data.top_setinfo;
815 auto bottom_part = chunk_data.chunk_setinfo - top_part;
816 TxIdx bottom_rep = dep_data.child;
817 auto& bottom_chunk_data =
m_tx_data[bottom_rep];
818 bottom_chunk_data.chunk_setinfo = bottom_part;
819 TxIdx top_rep = dep_data.parent;
820 auto& top_chunk_data =
m_tx_data[top_rep];
821 top_chunk_data.chunk_setinfo = top_part;
829 UpdateChunk<true>(top_part.transactions, dep_data.parent,
830 top_rep, bottom_part);
834 UpdateChunk<true>(bottom_part.transactions, dep_data.child,
835 bottom_rep, top_part);
844 Assume(top_chunk.chunk_rep == top_rep);
845 auto& bottom_chunk =
m_tx_data[bottom_rep];
846 Assume(bottom_chunk.chunk_rep == bottom_rep);
849 for (
auto tx : top_chunk.chunk_setinfo.transactions) {
851 num_deps += (tx_data.children & bottom_chunk.chunk_setinfo.transactions).Count();
853 if (num_deps == 0)
return TxIdx(-1);
856 for (
auto tx : top_chunk.chunk_setinfo.transactions) {
858 auto intersect = tx_data.children & bottom_chunk.chunk_setinfo.transactions;
859 auto count = intersect.Count();
861 for (
auto dep : tx_data.child_deps) {
863 if (bottom_chunk.chunk_setinfo.transactions[dep_data.child]) {
864 if (pick == 0)
return Activate(dep);
878 template<
bool DownWard>
883 SetType chunk_txn = chunk_data.chunk_setinfo.transactions;
892 SetType explored = chunk_txn;
896 FeeFrac best_other_chunk_feerate = chunk_data.chunk_setinfo.feerate;
901 uint64_t best_other_chunk_tiebreak{0};
902 for (
auto tx : chunk_txn) {
906 auto newly_reached = (DownWard ? tx_data.children : tx_data.parents) - explored;
907 explored |= newly_reached;
908 while (newly_reached.Any()) {
910 auto reached_chunk_rep =
m_tx_data[newly_reached.First()].chunk_rep;
911 auto& reached_chunk =
m_tx_data[reached_chunk_rep].chunk_setinfo;
912 newly_reached -= reached_chunk.transactions;
914 auto cmp = DownWard ? FeeRateCompare(best_other_chunk_feerate, reached_chunk.feerate)
915 : FeeRateCompare(reached_chunk.feerate, best_other_chunk_feerate);
916 if (cmp > 0)
continue;
918 if (cmp < 0 || tiebreak >= best_other_chunk_tiebreak) {
919 best_other_chunk_feerate = reached_chunk.feerate;
920 best_other_chunk_rep = reached_chunk_rep;
921 best_other_chunk_tiebreak = tiebreak;
926 if (best_other_chunk_rep ==
TxIdx(-1))
return TxIdx(-1);
927 if constexpr (DownWard) {
928 chunk_rep =
MergeChunks(chunk_rep, best_other_chunk_rep);
930 chunk_rep =
MergeChunks(best_other_chunk_rep, chunk_rep);
938 template<
bool DownWard>
941 auto chunk_rep =
m_tx_data[tx_idx].chunk_rep;
943 auto merged_rep = MergeStep<DownWard>(chunk_rep);
944 if (merged_rep ==
TxIdx(-1))
break;
945 chunk_rep = merged_rep;
968 MergeSequence<false>(dep_data.parent);
970 MergeSequence<true>(dep_data.child);
981 m_tx_data.resize(depgraph.PositionRange());
989 m_dep_data.reserve((num_transactions * num_transactions) / 4);
993 tx_data.chunk_rep = tx;
994 tx_data.chunk_setinfo.transactions = SetType::Singleton(tx);
995 tx_data.chunk_setinfo.feerate = depgraph.FeeRate(tx);
997 SetType parents = depgraph.GetReducedParents(tx);
998 for (
auto par : parents) {
1007 tx_data.parents.Set(par);
1009 par_tx_data.child_deps.push_back(dep_idx);
1010 par_tx_data.children.Set(tx);
1022 auto chunk_rep =
m_tx_data[tx].chunk_rep;
1025 chunk_rep = MergeStep<false>(chunk_rep);
1026 if (chunk_rep ==
TxIdx(-1))
break;
1036 if (tx_data.chunk_rep == tx) {
1052 if (chunk_data.chunk_rep != chunk)
continue;
1054 for (
int i = 0; i < 2; ++i) {
1057 auto result_up = MergeStep<false>(chunk);
1058 if (result_up !=
TxIdx(-1)) {
1064 auto result_down = MergeStep<true>(chunk);
1065 if (result_down !=
TxIdx(-1)) {
1080 if (tx_data.chunk_rep == tx) {
1102 if (chunk_data.chunk_rep != chunk)
continue;
1105 uint64_t candidate_tiebreak = 0;
1107 for (
auto tx : chunk_data.chunk_setinfo.transactions) {
1110 const auto children = std::span{tx_data.child_deps};
1111 for (
DepIdx dep_idx : children) {
1113 if (!dep_data.active)
continue;
1116 auto cmp = FeeRateCompare(dep_data.top_setinfo.feerate, chunk_data.chunk_setinfo.feerate);
1117 if (cmp <= 0)
continue;
1122 if (tiebreak < candidate_tiebreak)
continue;
1124 candidate_dep = dep_idx;
1125 candidate_tiebreak = tiebreak;
1149 if (tx_data.chunk_rep == tx) {
1169 auto& chunk_data =
m_tx_data[chunk_rep];
1170 Assume(chunk_data.chunk_rep == chunk_rep);
1172 bool move_pivot_down =
flags & 1;
1174 bool second_stage =
flags & 2;
1179 uint64_t candidate_tiebreak{0};
1180 bool have_any =
false;
1182 for (
auto tx_idx : chunk_data.chunk_setinfo.transactions) {
1183 const auto& tx_data =
m_tx_data[tx_idx];
1185 for (
auto dep_idx : tx_data.child_deps) {
1188 if (!dep_data.active)
continue;
1192 if (dep_data.top_setinfo.feerate << chunk_data.chunk_setinfo.feerate)
continue;
1195 if (move_pivot_down == dep_data.top_setinfo.transactions[pivot_idx])
continue;
1198 if (tiebreak > candidate_tiebreak) {
1199 candidate_tiebreak = tiebreak;
1200 candidate_dep = dep_idx;
1205 if (!have_any)
return true;
1208 if (candidate_tiebreak == 0) {
1218 auto parent_chunk_rep =
m_tx_data[dep_data.parent].chunk_rep;
1219 auto child_chunk_rep =
m_tx_data[dep_data.child].chunk_rep;
1222 auto merged_chunk_rep =
MergeChunks(child_chunk_rep, parent_chunk_rep);
1223 if (merged_chunk_rep !=
TxIdx(-1)) {
1236 if (move_pivot_down) {
1271 std::vector<DepGraphIndex>
ret;
1276 std::vector<std::pair<TxIdx, TxIdx>> ready_chunks;
1283 std::vector<std::pair<TxIdx, TxIdx>> chunk_deps(
m_tx_data.size(), {0, 0});
1288 std::vector<TxIdx> ready_tx;
1292 const auto& chl_data =
m_tx_data[chl_idx];
1293 chunk_deps[chl_idx].second = chl_data.parents.Count();
1294 auto chl_chunk_rep = chl_data.chunk_rep;
1295 chunk_reps.Set(chl_chunk_rep);
1296 for (
auto par_idx : chl_data.parents) {
1297 auto par_chunk_rep =
m_tx_data[par_idx].chunk_rep;
1298 chunk_deps[chl_chunk_rep].first += (par_chunk_rep != chl_chunk_rep);
1302 auto max_fallback_fn = [&](
TxIdx chunk_rep)
noexcept {
1303 auto& chunk =
m_tx_data[chunk_rep].chunk_setinfo.transactions;
1304 auto it = chunk.begin();
1307 while (it != chunk.end()) {
1308 if (fallback_order(*it,
ret) > 0)
ret = *it;
1315 auto tx_cmp_fn = [&](
const auto& a,
const auto& b)
noexcept {
1317 if (a == b)
return false;
1321 auto feerate_cmp = FeeRateCompare(a_feerate, b_feerate);
1322 if (feerate_cmp != 0)
return feerate_cmp < 0;
1324 if (a_feerate.size != b_feerate.size) {
1325 return a_feerate.size > b_feerate.size;
1328 auto fallback_cmp = fallback_order(a, b);
1329 if (fallback_cmp != 0)
return fallback_cmp > 0;
1337 auto chunk_cmp_fn = [&](
const auto& a,
const auto& b)
noexcept {
1339 if (a.first == b.first)
return false;
1341 auto& chunk_feerate_a =
m_tx_data[a.first].chunk_setinfo.feerate;
1342 auto& chunk_feerate_b =
m_tx_data[b.first].chunk_setinfo.feerate;
1343 auto feerate_cmp = FeeRateCompare(chunk_feerate_a, chunk_feerate_b);
1344 if (feerate_cmp != 0)
return feerate_cmp < 0;
1346 if (chunk_feerate_a.size != chunk_feerate_b.size) {
1347 return chunk_feerate_a.size > chunk_feerate_b.size;
1350 auto fallback_cmp = fallback_order(a.second, b.second);
1351 if (fallback_cmp != 0)
return fallback_cmp > 0;
1354 return a.second < b.second;
1357 for (
TxIdx chunk_rep : chunk_reps) {
1358 if (chunk_deps[chunk_rep].first == 0) {
1359 ready_chunks.emplace_back(chunk_rep, max_fallback_fn(chunk_rep));
1362 std::make_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
1364 while (!ready_chunks.empty()) {
1365 auto [chunk_rep, _rnd] = ready_chunks.front();
1366 std::pop_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
1367 ready_chunks.pop_back();
1369 Assume(chunk_deps[chunk_rep].first == 0);
1370 const auto& chunk_txn =
m_tx_data[chunk_rep].chunk_setinfo.transactions;
1372 Assume(ready_tx.empty());
1373 for (
TxIdx tx_idx : chunk_txn) {
1374 if (chunk_deps[tx_idx].second == 0) ready_tx.push_back(tx_idx);
1376 Assume(!ready_tx.empty());
1377 std::make_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
1380 while (!ready_tx.empty()) {
1382 auto tx_idx = ready_tx.front();
1383 std::pop_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
1384 ready_tx.pop_back();
1386 ret.push_back(tx_idx);
1389 for (
TxIdx chl_idx : tx_data.children) {
1392 Assume(chunk_deps[chl_idx].second > 0);
1393 if (--chunk_deps[chl_idx].second == 0 && chunk_txn[chl_idx]) {
1395 ready_tx.push_back(chl_idx);
1396 std::push_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
1399 if (chl_data.chunk_rep != chunk_rep) {
1400 Assume(chunk_deps[chl_data.chunk_rep].first > 0);
1401 if (--chunk_deps[chl_data.chunk_rep].first == 0) {
1403 ready_chunks.emplace_back(chl_data.chunk_rep, max_fallback_fn(chl_data.chunk_rep));
1404 std::push_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
1429 std::vector<FeeFrac>
ret;
1435 std::sort(
ret.begin(),
ret.end(), std::greater{});
1448 std::vector<std::pair<TxIdx, TxIdx>> expected_dependencies;
1449 std::vector<std::tuple<TxIdx, TxIdx, DepIdx>> all_dependencies;
1450 std::vector<std::tuple<TxIdx, TxIdx, DepIdx>> active_dependencies;
1451 for (
auto parent_idx : depgraph.
Positions()) {
1453 expected_dependencies.emplace_back(parent_idx, child_idx);
1458 all_dependencies.emplace_back(dep_data.parent, dep_data.child, dep_idx);
1461 active_dependencies.emplace_back(dep_data.parent, dep_data.child, dep_idx);
1464 std::sort(expected_dependencies.begin(), expected_dependencies.end());
1465 std::sort(all_dependencies.begin(), all_dependencies.end());
1466 assert(expected_dependencies.size() == all_dependencies.size());
1467 for (
size_t i = 0; i < expected_dependencies.size(); ++i) {
1468 assert(expected_dependencies[i] ==
1469 std::make_pair(std::get<0>(all_dependencies[i]),
1470 std::get<1>(all_dependencies[i])));
1476 for (
auto tx_idx: depgraph.
Positions()) {
1478 if (
m_tx_data[tx_idx].chunk_rep == tx_idx) {
1479 const auto& chunk_data =
m_tx_data[tx_idx];
1482 for (
auto chunk_tx : chunk_data.chunk_setinfo.transactions) {
1489 SetType expected_chunk = SetType::Singleton(tx_idx);
1491 auto old = expected_chunk;
1492 size_t active_dep_count{0};
1493 for (
const auto& [par, chl, _dep] : active_dependencies) {
1494 if (expected_chunk[par] || expected_chunk[chl]) {
1495 expected_chunk.Set(par);
1496 expected_chunk.Set(chl);
1500 if (old == expected_chunk) {
1501 assert(expected_chunk.Count() == active_dep_count + 1);
1505 assert(chunk_data.chunk_setinfo.transactions == expected_chunk);
1507 assert(chunk_data.chunk_setinfo.feerate ==
1508 depgraph.
FeeRate(chunk_data.chunk_setinfo.transactions));
1517 const auto& tx_data =
m_tx_data[tx_idx];
1521 assert(
m_tx_data[tx_data.chunk_rep].chunk_setinfo.transactions[tx_idx]);
1526 std::vector<DepIdx> expected_child_deps;
1527 for (
const auto& [par_idx, chl_idx, dep_idx] : all_dependencies) {
1528 if (tx_idx == par_idx) {
1529 assert(tx_data.children[chl_idx]);
1530 expected_child_deps.push_back(dep_idx);
1533 std::sort(expected_child_deps.begin(), expected_child_deps.end());
1534 auto child_deps_copy = tx_data.child_deps;
1535 std::sort(child_deps_copy.begin(), child_deps_copy.end());
1536 assert(expected_child_deps == child_deps_copy);
1542 for (
const auto& [par_idx, chl_idx, dep_idx] : active_dependencies) {
1547 SetType expected_top = SetType::Singleton(par_idx);
1549 auto old = expected_top;
1550 for (
const auto& [par2_idx, chl2_idx, dep2_idx] : active_dependencies) {
1551 if (dep2_idx != dep_idx && (expected_top[par2_idx] || expected_top[chl2_idx])) {
1552 expected_top.Set(par2_idx);
1553 expected_top.Set(chl2_idx);
1556 if (old == expected_top)
break;
1558 assert(!expected_top[chl_idx]);
1559 assert(dep_data.top_setinfo.transactions == expected_top);
1561 assert(dep_data.top_setinfo.feerate ==
1562 depgraph.
FeeRate(dep_data.top_setinfo.transactions));
1576 SetType nonminimal_reps;
1581 assert(!nonminimal_reps[chunk_rep]);
1582 nonminimal_reps.Set(chunk_rep);
1608template<
typename SetType>
1609std::tuple<std::vector<DepGraphIndex>, bool, uint64_t>
Linearize(
1611 uint64_t max_iterations,
1614 std::span<const DepGraphIndex> old_linearization = {},
1615 bool is_topological =
true)
noexcept
1618 SpanningForestState forest(depgraph, rng_seed);
1619 if (!old_linearization.empty()) {
1620 forest.LoadLinearization(old_linearization);
1621 if (!is_topological) forest.MakeTopological();
1623 forest.MakeTopological();
1627 if (forest.GetCost() < max_iterations) {
1628 forest.StartOptimizing();
1630 if (!forest.OptimizeStep())
break;
1631 }
while (forest.GetCost() < max_iterations);
1635 bool optimal =
false;
1636 if (forest.GetCost() < max_iterations) {
1637 forest.StartMinimizing();
1639 if (!forest.MinimizeStep()) {
1643 }
while (forest.GetCost() < max_iterations);
1645 return {forest.GetLinearization(fallback_order), optimal, forest.GetCost()};
1664template<
typename SetType>
1758 for (
int pass = 0; pass < 2; ++pass) {
1759 int rev = !(pass & 1);
1761 entries[SENTINEL].prev_group = SENTINEL;
1767 DepGraphIndex idx = linearization[rev ? linearization.size() - 1 - i : i];
1771 entries[cur_group].group = SetType::Singleton(idx);
1773 entries[cur_group].feerate = depgraph.
FeeRate(idx);
1774 if (rev) entries[cur_group].feerate.
fee = -entries[cur_group].feerate.fee;
1775 entries[cur_group].prev_tx = NO_PREV_TX;
1776 entries[cur_group].first_tx = cur_group;
1778 entries[cur_group].prev_group = entries[SENTINEL].prev_group;
1779 entries[SENTINEL].prev_group = cur_group;
1785 while (entries[cur_group].feerate >> entries[prev_group].feerate) {
1788 Assume(cur_group == entries[next_group].prev_group);
1789 Assume(prev_group == entries[cur_group].prev_group);
1793 Assume(cur_group != SENTINEL);
1794 Assume(prev_group != SENTINEL);
1795 if (entries[cur_group].deps.Overlaps(entries[prev_group].group)) {
1799 entries[cur_group].group |= entries[prev_group].group;
1800 entries[cur_group].deps |= entries[prev_group].deps;
1801 entries[cur_group].feerate += entries[prev_group].feerate;
1803 entries[entries[cur_group].first_tx].prev_tx = prev_group;
1805 entries[cur_group].first_tx = entries[prev_group].first_tx;
1807 prev_group = entries[prev_group].prev_group;
1808 entries[cur_group].prev_group = prev_group;
1811 DepGraphIndex preprev_group = entries[prev_group].prev_group;
1814 entries[next_group].prev_group = prev_group;
1815 entries[prev_group].prev_group = cur_group;
1816 entries[cur_group].prev_group = preprev_group;
1819 next_group = prev_group;
1820 prev_group = preprev_group;
1828 while (cur_group != SENTINEL) {
1834 *(linearization.begin() + (done++)) = cur_tx - 1;
1835 cur_tx = entries[cur_tx].prev_tx;
1836 }
while (cur_tx != NO_PREV_TX);
1839 *(linearization.end() - (++done)) = cur_tx - 1;
1840 cur_tx = entries[cur_tx].prev_tx;
1841 }
while (cur_tx != NO_PREV_TX);
1843 cur_group = entries[cur_group].prev_group;
1845 Assume(done == linearization.size());
#define Assume(val)
Assume is the identity function.
constexpr uint64_t rand64() noexcept
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
bool randbool() noexcept
Generate a random boolean.
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
bool empty() const noexcept
Test whether the contents of this deque is empty.
void clear() noexcept
Resize the deque to be size 0.
void push_back(T &&elem)
Move-construct a new element at the end of the deque.
void pop_front()
Remove the first element of the deque.
size_t size() const noexcept
Get the number of elements in this deque.
void emplace_back(Args &&... args)
Construct a new element at the end of the deque.
T & front() noexcept
Get a mutable reference to the first element of the deque.
void reserve(size_t capacity)
Increase the capacity to capacity.
T & back() noexcept
Get a mutable reference to the last element of the deque.
Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors,...
unsigned CountDependencies() const noexcept
const SetType & Ancestors(DepGraphIndex i) const noexcept
Get the ancestors of a given transaction i.
FeeFrac & FeeRate(DepGraphIndex i) noexcept
Get the mutable feerate of a given transaction i.
SetType GetReducedChildren(DepGraphIndex i) const noexcept
Compute the (reduced) set of children of node i in this graph.
SetType GetReducedParents(DepGraphIndex i) const noexcept
Compute the (reduced) set of parents of node i in this graph.
void AppendTopo(std::vector< DepGraphIndex > &list, const SetType &select) const noexcept
Append the entries of select to list in a topologically valid order.
const FeeFrac & FeeRate(DepGraphIndex i) const noexcept
Get the feerate of a given transaction i.
SetType GetConnectedComponent(const SetType &todo, DepGraphIndex tx) const noexcept
Get the connected component within the subset "todo" that contains tx (which must be in todo).
bool IsConnected() const noexcept
Determine if this entire graph is connected.
bool IsConnected(const SetType &subset) const noexcept
Determine if a subset is connected.
DepGraphIndex PositionRange() const noexcept
Get the range of positions in this DepGraph.
SetType FindConnectedComponent(const SetType &todo) const noexcept
Find some connected component within the subset "todo" of this graph.
DepGraphIndex AddTransaction(const FeeFrac &feefrac) noexcept
Add a new unconnected transaction to this transaction graph (in the first available position),...
void RemoveTransactions(const SetType &del) noexcept
Remove the specified positions from this DepGraph.
auto TxCount() const noexcept
Get the number of transactions in the graph.
std::vector< Entry > entries
Data for each transaction.
const SetType & Descendants(DepGraphIndex i) const noexcept
Get the descendants of a given transaction i.
friend bool operator==(const DepGraph &a, const DepGraph &b) noexcept
Equality operator (primarily for testing purposes).
size_t DynamicMemoryUsage() const noexcept
DepGraph() noexcept=default
SetType m_used
Which positions are used.
const SetType & Positions() const noexcept
Get the set of transactions positions in use.
void Compact() noexcept
Reduce memory usage if possible.
FeeFrac FeeRate(const SetType &elems) const noexcept
Compute the aggregate feerate of a set of nodes in this graph.
void AddDependencies(const SetType &parents, DepGraphIndex child) noexcept
Modify this transaction graph, adding multiple parents to a specified child.
bool IsAcyclic() const noexcept
Check if this graph is acyclic.
Class to represent the internal state of the spanning-forest linearization (SFL) algorithm.
void UpdateChunk(const SetType &chunk, TxIdx query, TxIdx chunk_rep, const SetInfo< SetType > &dep_change) noexcept
Update a chunk:
TxIdx PickRandomTx(const SetType &tx_idxs) noexcept
Pick a random transaction within a set (which must be non-empty).
std::vector< TxData > m_tx_data
Information about each transaction (and chunks).
InsecureRandomContext m_rng
Internal RNG.
DepGraphIndex TxIdx
Data type to represent indexing into m_tx_data.
bool OptimizeStep() noexcept
Try to improve the forest.
uint64_t GetCost() const noexcept
Determine how much work was performed so far.
TxIdx Activate(DepIdx dep_idx) noexcept
Make a specified inactive dependency active.
void Improve(DepIdx dep_idx) noexcept
Split a chunk, and then merge the resulting two chunks to make the graph topological again.
std::vector< FeeFrac > GetDiagram() const noexcept
Get the diagram for the current state, which must be topological.
SpanningForestState(const DepGraph< SetType > &depgraph LIFETIMEBOUND, uint64_t rng_seed) noexcept
Construct a spanning forest for the given DepGraph, with every transaction in its own chunk (not topo...
std::vector< DepData > m_dep_data
Information about each dependency.
void MakeTopological() noexcept
Make state topological.
TxIdx MergeChunks(TxIdx top_rep, TxIdx bottom_rep) noexcept
Activate a dependency from the chunk represented by bottom_idx to the chunk represented by top_idx.
void StartMinimizing() noexcept
Initialize data structure for minimizing the chunks.
VecDeque< std::tuple< TxIdx, TxIdx, unsigned > > m_nonminimal_chunks
A FIFO of chunk representatives with a pivot transaction in them, and a flag to indicate their status...
TxIdx MergeStep(TxIdx chunk_rep) noexcept
Perform an upward or downward merge step, on the specified chunk representative.
void SanityCheck(const DepGraph< SetType > &depgraph) const
Verify internal consistency of the data structure.
void StartOptimizing() noexcept
Initialize the data structure for optimization.
VecDeque< TxIdx > m_suboptimal_chunks
A FIFO of chunk representatives of chunks that may be improved still.
void LoadLinearization(std::span< const DepGraphIndex > old_linearization) noexcept
Load an existing linearization.
bool MinimizeStep() noexcept
Try to reduce a chunk's size.
uint32_t DepIdx
Data type to represent indexing into m_dep_data.
std::vector< DepGraphIndex > GetLinearization(const StrongComparator< DepGraphIndex > auto &fallback_order) const noexcept
Construct a topologically-valid linearization from the current forest state.
SetType m_transaction_idxs
The set of all TxIdx's of transactions in the cluster indexing into m_tx_data.
const DepGraph< SetType > & m_depgraph
The DepGraph we are trying to linearize.
void MergeSequence(TxIdx tx_idx) noexcept
Perform an upward or downward merge sequence on the specified transaction.
uint64_t m_cost
The number of updated transactions in activations/deactivations.
void Deactivate(DepIdx dep_idx) noexcept
Make a specified active dependency inactive.
Concept for function objects that return std::strong_ordering when invoked with two Args.
std::vector< FeeFrac > ChunkLinearization(const DepGraph< SetType > &depgraph, std::span< const DepGraphIndex > linearization) noexcept
Compute the feerates of the chunks of linearization.
std::compare_three_way IndexTxOrder
Simple default transaction ordering function for SpanningForestState::GetLinearization() and Lineariz...
uint32_t DepGraphIndex
Data type to represent transaction indices in DepGraphs and the clusters they represent.
void PostLinearize(const DepGraph< SetType > &depgraph, std::span< DepGraphIndex > linearization)
Improve a given linearization.
std::tuple< std::vector< DepGraphIndex >, bool, uint64_t > Linearize(const DepGraph< SetType > &depgraph, uint64_t max_iterations, uint64_t rng_seed, const StrongComparator< DepGraphIndex > auto &fallback_order, std::span< const DepGraphIndex > old_linearization={}, bool is_topological=true) noexcept
Find or improve a linearization for a cluster.
std::vector< SetInfo< SetType > > ChunkLinearizationInfo(const DepGraph< SetType > &depgraph, std::span< const DepGraphIndex > linearization) noexcept
Compute the chunks of linearization as SetInfos.
static size_t DynamicUsage(const int8_t &v)
Dynamic memory usage for built-in types is zero.
Data structure storing a fee and size, ordered by increasing fee/size.
bool IsEmpty() const noexcept
Check if this is empty (size and fee are 0).
Information about a single transaction.
SetType descendants
All descendants of the transaction (including itself).
friend bool operator==(const Entry &, const Entry &) noexcept=default
Equality operator (primarily for testing purposes).
Entry() noexcept=default
Construct an empty entry.
FeeFrac feerate
Fee and size of transaction itself.
SetType ancestors
All ancestors of the transaction (including itself).
A set of transactions together with their aggregate feerate.
SetInfo(const DepGraph< SetType > &depgraph, DepGraphIndex pos) noexcept
Construct a SetInfo for a given transaction in a depgraph.
SetInfo operator-(const SetInfo &other) const noexcept
Compute the difference between this and other SetInfo (which must be a subset).
FeeFrac feerate
Their combined fee and size.
SetInfo() noexcept=default
Construct a SetInfo for the empty set.
void Set(const DepGraph< SetType > &depgraph, DepGraphIndex pos) noexcept
Add a transaction to this SetInfo (which must not yet be in it).
SetType transactions
The transactions in the set.
friend void swap(SetInfo &a, SetInfo &b) noexcept
Swap two SetInfo objects.
SetInfo(const DepGraph< SetType > &depgraph, const SetType &txn) noexcept
Construct a SetInfo for a set of transactions in a depgraph.
SetInfo & operator|=(const SetInfo &other) noexcept
Add the transactions of other to this SetInfo (no overlap allowed).
SetInfo & operator-=(const SetInfo &other) noexcept
Remove the transactions of other from this SetInfo (which must be a subset).
friend bool operator==(const SetInfo &, const SetInfo &) noexcept=default
Permit equality testing.
Structure with information about a single dependency.
bool active
Whether this dependency is active.
SetInfo< SetType > top_setinfo
(Only if this dependency is active) the would-be top chunk and its feerate that would be formed if th...
TxIdx parent
What the parent and child transactions are.
Structure with information about a single transaction.
std::vector< DepIdx > child_deps
The dependencies to children of this transaction.
SetType parents
The set of parent transactions of this transaction.
SetType children
The set of child transactions of this transaction.
TxIdx chunk_rep
Which transaction holds the chunk_setinfo for the chunk this transaction is in (the representative fo...
SetInfo< SetType > chunk_setinfo
(Only if this transaction is the representative for the chunk it is in) the total chunk set and feera...