5#ifndef BITCOIN_CLUSTER_LINEARIZE_H
6#define BITCOIN_CLUSTER_LINEARIZE_H
28template<
typename SetType>
60 if (a.m_used != b.m_used)
return false;
62 for (
auto idx : a.m_used) {
63 if (a.entries[idx] != b.entries[idx])
return false;
92 Assume(mapping.size() == depgraph.PositionRange());
93 Assume((pos_range == 0) == (depgraph.TxCount() == 0));
95 auto new_idx = mapping[i];
96 Assume(new_idx < pos_range);
98 entries[new_idx].ancestors = SetType::Singleton(new_idx);
99 entries[new_idx].descendants = SetType::Singleton(new_idx);
102 entries[new_idx].feerate = depgraph.entries[i].feerate;
107 for (
auto j : depgraph.GetReducedParents(i)) parents.Set(mapping[j]);
136 static constexpr auto ALL_POSITIONS = SetType::Fill(SetType::Size());
137 auto available = ALL_POSITIONS -
m_used;
140 if (new_idx ==
entries.size()) {
141 entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
143 entries[new_idx] =
Entry(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
169 entry.ancestors &=
m_used;
170 entry.descendants &=
m_used;
184 for (
auto par : parents -
Ancestors(child)) {
189 if (par_anc.None())
return;
191 const auto& chl_des =
entries[child].descendants;
192 for (
auto anc_of_par : par_anc) {
193 entries[anc_of_par].descendants |= chl_des;
197 entries[dec_of_chl].ancestors |= par_anc;
213 for (
auto parent : parents) {
214 if (parents[parent]) {
234 for (
auto child : children) {
235 if (children[child]) {
250 for (
auto pos : elems)
ret +=
entries[pos].feerate;
268 auto to_add = SetType::Singleton(tx);
272 for (
auto add : to_add) {
278 }
while (to_add.Any());
291 if (todo.None())
return todo;
314 void AppendTopo(std::vector<DepGraphIndex>& list,
const SetType& select)
const noexcept
317 for (
auto i : select) list.push_back(i);
319 const auto a_anc_count = entries[a].ancestors.Count();
320 const auto b_anc_count = entries[b].ancestors.Count();
321 if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count;
359template<
typename SetType>
386 feerate += depgraph.FeeRate(pos);
417 swap(a.transactions, b.transactions);
418 swap(a.feerate, b.feerate);
426template<
typename SetType>
429 std::vector<SetInfo<SetType>>
ret;
434 while (!
ret.empty() && new_chunk.
feerate >>
ret.back().feerate) {
435 new_chunk |=
ret.back();
439 ret.emplace_back(std::move(new_chunk));
446template<
typename SetType>
449 std::vector<FeeFrac>
ret;
452 auto new_chunk = depgraph.FeeRate(i);
454 while (!
ret.empty() && new_chunk >>
ret.back()) {
455 new_chunk +=
ret.back();
459 ret.push_back(std::move(new_chunk));
598template<
typename SetType>
656 template<
bool Subtract>
660 for (
auto tx_idx : chunk) {
663 tx_data.chunk_rep = chunk_rep;
666 auto child_deps = std::span{tx_data.child_deps};
667 for (
auto dep_idx : child_deps) {
669 Assume(dep_entry.parent == tx_idx);
671 if (!dep_entry.active)
continue;
674 if (dep_entry.top_setinfo.transactions[query]) {
675 if constexpr (Subtract) {
676 dep_entry.top_setinfo -= dep_change;
678 dep_entry.top_setinfo |= dep_change;
690 auto& child_tx_data =
m_tx_data[dep_data.child];
691 auto& parent_tx_data =
m_tx_data[dep_data.parent];
694 Assume(parent_tx_data.chunk_rep != child_tx_data.chunk_rep);
695 auto& par_chunk_data =
m_tx_data[parent_tx_data.chunk_rep];
696 auto& chl_chunk_data =
m_tx_data[child_tx_data.chunk_rep];
697 TxIdx top_rep = parent_tx_data.chunk_rep;
698 auto top_part = par_chunk_data.chunk_setinfo;
699 auto bottom_part = chl_chunk_data.chunk_setinfo;
701 par_chunk_data.chunk_setinfo |= bottom_part;
702 m_cost += par_chunk_data.chunk_setinfo.transactions.Count();
723 UpdateChunk<false>(top_part.transactions, dep_data.parent,
724 top_rep, bottom_part);
729 UpdateChunk<false>(bottom_part.transactions, dep_data.child,
732 dep_data.active =
true;
733 dep_data.top_setinfo = top_part;
742 auto& parent_tx_data =
m_tx_data[dep_data.parent];
744 dep_data.active =
false;
746 auto& chunk_data =
m_tx_data[parent_tx_data.chunk_rep];
747 m_cost += chunk_data.chunk_setinfo.transactions.Count();
748 auto top_part = dep_data.top_setinfo;
749 auto bottom_part = chunk_data.chunk_setinfo - top_part;
750 TxIdx bottom_rep = dep_data.child;
751 auto& bottom_chunk_data =
m_tx_data[bottom_rep];
752 bottom_chunk_data.chunk_setinfo = bottom_part;
753 TxIdx top_rep = dep_data.parent;
754 auto& top_chunk_data =
m_tx_data[top_rep];
755 top_chunk_data.chunk_setinfo = top_part;
763 UpdateChunk<true>(top_part.transactions, dep_data.parent,
764 top_rep, bottom_part);
768 UpdateChunk<true>(bottom_part.transactions, dep_data.child,
769 bottom_rep, top_part);
777 Assume(top_chunk.chunk_rep == top_rep);
778 auto& bottom_chunk =
m_tx_data[bottom_rep];
779 Assume(bottom_chunk.chunk_rep == bottom_rep);
782 for (
auto tx : top_chunk.chunk_setinfo.transactions) {
784 num_deps += (tx_data.children & bottom_chunk.chunk_setinfo.transactions).Count();
789 for (
auto tx : top_chunk.chunk_setinfo.transactions) {
791 auto intersect = tx_data.children & bottom_chunk.chunk_setinfo.transactions;
792 auto count = intersect.Count();
794 for (
auto dep : tx_data.child_deps) {
796 if (bottom_chunk.chunk_setinfo.transactions[dep_data.child]) {
797 if (pick == 0)
return Activate(dep);
811 template<
bool DownWard>
816 SetType chunk_txn = chunk_data.chunk_setinfo.transactions;
825 SetType explored = chunk_txn;
829 FeeFrac best_other_chunk_feerate = chunk_data.chunk_setinfo.feerate;
834 uint64_t best_other_chunk_tiebreak{0};
835 for (
auto tx : chunk_txn) {
839 auto newly_reached = (DownWard ? tx_data.children : tx_data.parents) - explored;
840 explored |= newly_reached;
841 while (newly_reached.Any()) {
843 auto reached_chunk_rep =
m_tx_data[newly_reached.First()].chunk_rep;
844 auto& reached_chunk =
m_tx_data[reached_chunk_rep].chunk_setinfo;
845 newly_reached -= reached_chunk.transactions;
847 auto cmp = DownWard ? FeeRateCompare(best_other_chunk_feerate, reached_chunk.feerate)
848 : FeeRateCompare(reached_chunk.feerate, best_other_chunk_feerate);
849 if (cmp > 0)
continue;
851 if (cmp < 0 || tiebreak >= best_other_chunk_tiebreak) {
852 best_other_chunk_feerate = reached_chunk.feerate;
853 best_other_chunk_rep = reached_chunk_rep;
854 best_other_chunk_tiebreak = tiebreak;
859 if (best_other_chunk_rep ==
TxIdx(-1))
return TxIdx(-1);
860 if constexpr (DownWard) {
861 chunk_rep =
MergeChunks(chunk_rep, best_other_chunk_rep);
863 chunk_rep =
MergeChunks(best_other_chunk_rep, chunk_rep);
871 template<
bool DownWard>
874 auto chunk_rep =
m_tx_data[tx_idx].chunk_rep;
876 auto merged_rep = MergeStep<DownWard>(chunk_rep);
877 if (merged_rep ==
TxIdx(-1))
break;
878 chunk_rep = merged_rep;
901 MergeSequence<false>(dep_data.parent);
903 MergeSequence<true>(dep_data.child);
913 m_tx_data.resize(depgraph.PositionRange());
921 m_dep_data.reserve((num_transactions * num_transactions) / 4);
925 tx_data.chunk_rep = tx;
926 tx_data.chunk_setinfo.transactions = SetType::Singleton(tx);
927 tx_data.chunk_setinfo.feerate = depgraph.FeeRate(tx);
929 SetType parents = depgraph.GetReducedParents(tx);
930 for (
auto par : parents) {
939 tx_data.parents.Set(par);
941 par_tx_data.child_deps.push_back(dep_idx);
942 par_tx_data.children.Set(tx);
954 auto chunk_rep =
m_tx_data[tx].chunk_rep;
957 chunk_rep = MergeStep<false>(chunk_rep);
958 if (chunk_rep ==
TxIdx(-1))
break;
968 if (tx_data.chunk_rep == tx) {
984 if (chunk_data.chunk_rep != chunk)
continue;
986 for (
int i = 0; i < 2; ++i) {
989 auto result_up = MergeStep<false>(chunk);
990 if (result_up !=
TxIdx(-1)) {
996 auto result_down = MergeStep<true>(chunk);
997 if (result_down !=
TxIdx(-1)) {
1012 if (tx_data.chunk_rep == tx) {
1034 if (chunk_data.chunk_rep != chunk)
continue;
1037 uint64_t candidate_tiebreak = 0;
1039 for (
auto tx : chunk_data.chunk_setinfo.transactions) {
1042 const auto children = std::span{tx_data.child_deps};
1043 for (
DepIdx dep_idx : children) {
1045 if (!dep_data.active)
continue;
1048 auto cmp = FeeRateCompare(dep_data.top_setinfo.feerate, chunk_data.chunk_setinfo.feerate);
1049 if (cmp <= 0)
continue;
1054 if (tiebreak < candidate_tiebreak)
continue;
1056 candidate_dep = dep_idx;
1057 candidate_tiebreak = tiebreak;
1076 std::vector<DepGraphIndex>
ret;
1080 std::vector<std::pair<TxIdx, uint64_t>> ready_chunks;
1087 std::vector<std::pair<TxIdx, TxIdx>> chunk_deps(
m_tx_data.size(), {0, 0});
1091 std::vector<TxIdx> ready_tx;
1095 const auto& chl_data =
m_tx_data[chl_idx];
1096 chunk_deps[chl_idx].second = chl_data.parents.Count();
1097 auto chl_chunk_rep = chl_data.chunk_rep;
1098 chunk_reps.Set(chl_chunk_rep);
1099 for (
auto par_idx : chl_data.parents) {
1100 auto par_chunk_rep =
m_tx_data[par_idx].chunk_rep;
1101 chunk_deps[chl_chunk_rep].first += (par_chunk_rep != chl_chunk_rep);
1106 auto chunk_cmp_fn = [&](
const std::pair<TxIdx, uint64_t>& a,
const std::pair<TxIdx, uint64_t>& b)
noexcept {
1109 Assume(chunk_a.chunk_rep == a.first);
1110 Assume(chunk_b.chunk_rep == b.first);
1112 if (chunk_a.chunk_setinfo.feerate != chunk_b.chunk_setinfo.feerate) {
1113 return chunk_a.chunk_setinfo.feerate < chunk_b.chunk_setinfo.feerate;
1116 if (a.second != b.second)
return a.second < b.second;
1118 return a.first < b.first;
1120 for (
TxIdx chunk_rep : chunk_reps) {
1121 if (chunk_deps[chunk_rep].first == 0) ready_chunks.emplace_back(chunk_rep,
m_rng.
rand64());
1123 std::make_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
1125 while (!ready_chunks.empty()) {
1126 auto [chunk_rep, _rnd] = ready_chunks.front();
1127 std::pop_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
1128 ready_chunks.pop_back();
1130 Assume(chunk_deps[chunk_rep].first == 0);
1131 const auto& chunk_txn =
m_tx_data[chunk_rep].chunk_setinfo.transactions;
1133 for (
TxIdx tx_idx : chunk_txn) {
1134 if (chunk_deps[tx_idx].second == 0) {
1135 ready_tx.push_back(tx_idx);
1138 Assume(!ready_tx.empty());
1141 while (!ready_tx.empty()) {
1144 if (pos != ready_tx.size() - 1) std::swap(ready_tx.back(), ready_tx[pos]);
1146 auto tx_idx = ready_tx.back();
1147 Assume(chunk_txn[tx_idx]);
1148 ready_tx.pop_back();
1150 ret.push_back(tx_idx);
1153 for (
TxIdx chl_idx : tx_data.children) {
1156 Assume(chunk_deps[chl_idx].second > 0);
1157 if (--chunk_deps[chl_idx].second == 0 && chunk_txn[chl_idx]) {
1159 ready_tx.push_back(chl_idx);
1162 if (chl_data.chunk_rep != chunk_rep) {
1163 Assume(chunk_deps[chl_data.chunk_rep].first > 0);
1164 if (--chunk_deps[chl_data.chunk_rep].first == 0) {
1166 ready_chunks.emplace_back(chl_data.chunk_rep,
m_rng.
rand64());
1167 std::push_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
1188 std::vector<FeeFrac>
ret;
1194 std::sort(
ret.begin(),
ret.end(), std::greater{});
1207 std::vector<std::pair<TxIdx, TxIdx>> expected_dependencies;
1208 std::vector<std::tuple<TxIdx, TxIdx, DepIdx>> all_dependencies;
1209 std::vector<std::tuple<TxIdx, TxIdx, DepIdx>> active_dependencies;
1210 for (
auto parent_idx : depgraph.
Positions()) {
1212 expected_dependencies.emplace_back(parent_idx, child_idx);
1217 all_dependencies.emplace_back(dep_data.parent, dep_data.child, dep_idx);
1220 active_dependencies.emplace_back(dep_data.parent, dep_data.child, dep_idx);
1223 std::sort(expected_dependencies.begin(), expected_dependencies.end());
1224 std::sort(all_dependencies.begin(), all_dependencies.end());
1225 assert(expected_dependencies.size() == all_dependencies.size());
1226 for (
size_t i = 0; i < expected_dependencies.size(); ++i) {
1227 assert(expected_dependencies[i] ==
1228 std::make_pair(std::get<0>(all_dependencies[i]),
1229 std::get<1>(all_dependencies[i])));
1235 for (
auto tx_idx: depgraph.
Positions()) {
1237 if (
m_tx_data[tx_idx].chunk_rep == tx_idx) {
1238 const auto& chunk_data =
m_tx_data[tx_idx];
1241 for (
auto chunk_tx : chunk_data.chunk_setinfo.transactions) {
1248 SetType expected_chunk = SetType::Singleton(tx_idx);
1250 auto old = expected_chunk;
1251 size_t active_dep_count{0};
1252 for (
const auto& [par, chl, _dep] : active_dependencies) {
1253 if (expected_chunk[par] || expected_chunk[chl]) {
1254 expected_chunk.Set(par);
1255 expected_chunk.Set(chl);
1259 if (old == expected_chunk) {
1260 assert(expected_chunk.Count() == active_dep_count + 1);
1264 assert(chunk_data.chunk_setinfo.transactions == expected_chunk);
1266 assert(chunk_data.chunk_setinfo.feerate ==
1267 depgraph.
FeeRate(chunk_data.chunk_setinfo.transactions));
1276 const auto& tx_data =
m_tx_data[tx_idx];
1280 assert(
m_tx_data[tx_data.chunk_rep].chunk_setinfo.transactions[tx_idx]);
1285 std::vector<DepIdx> expected_child_deps;
1286 for (
const auto& [par_idx, chl_idx, dep_idx] : all_dependencies) {
1287 if (tx_idx == par_idx) {
1288 assert(tx_data.children[chl_idx]);
1289 expected_child_deps.push_back(dep_idx);
1292 std::sort(expected_child_deps.begin(), expected_child_deps.end());
1293 auto child_deps_copy = tx_data.child_deps;
1294 std::sort(child_deps_copy.begin(), child_deps_copy.end());
1295 assert(expected_child_deps == child_deps_copy);
1301 for (
const auto& [par_idx, chl_idx, dep_idx] : active_dependencies) {
1306 SetType expected_top = SetType::Singleton(par_idx);
1308 auto old = expected_top;
1309 for (
const auto& [par2_idx, chl2_idx, dep2_idx] : active_dependencies) {
1310 if (dep2_idx != dep_idx && (expected_top[par2_idx] || expected_top[chl2_idx])) {
1311 expected_top.Set(par2_idx);
1312 expected_top.Set(chl2_idx);
1315 if (old == expected_top)
break;
1317 assert(!expected_top[chl_idx]);
1318 assert(dep_data.top_setinfo.transactions == expected_top);
1320 assert(dep_data.top_setinfo.feerate ==
1321 depgraph.
FeeRate(dep_data.top_setinfo.transactions));
1350template<
typename SetType>
1351std::tuple<std::vector<DepGraphIndex>, bool, uint64_t>
Linearize(
const DepGraph<SetType>& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span<const DepGraphIndex> old_linearization = {})
noexcept
1354 SpanningForestState forest(depgraph, rng_seed);
1355 if (!old_linearization.empty()) {
1356 forest.LoadLinearization(old_linearization);
1358 forest.MakeTopological();
1362 bool optimal =
false;
1363 if (forest.GetCost() < max_iterations) {
1364 forest.StartOptimizing();
1366 if (!forest.OptimizeStep()) {
1370 }
while (forest.GetCost() < max_iterations);
1372 return {forest.GetLinearization(), optimal, forest.GetCost()};
1391template<
typename SetType>
1485 for (
int pass = 0; pass < 2; ++pass) {
1486 int rev = !(pass & 1);
1488 entries[SENTINEL].prev_group = SENTINEL;
1494 DepGraphIndex idx = linearization[rev ? linearization.size() - 1 - i : i];
1498 entries[cur_group].group = SetType::Singleton(idx);
1500 entries[cur_group].feerate = depgraph.
FeeRate(idx);
1501 if (rev) entries[cur_group].feerate.
fee = -entries[cur_group].feerate.fee;
1502 entries[cur_group].prev_tx = NO_PREV_TX;
1503 entries[cur_group].first_tx = cur_group;
1505 entries[cur_group].prev_group = entries[SENTINEL].prev_group;
1506 entries[SENTINEL].prev_group = cur_group;
1512 while (entries[cur_group].feerate >> entries[prev_group].feerate) {
1515 Assume(cur_group == entries[next_group].prev_group);
1516 Assume(prev_group == entries[cur_group].prev_group);
1520 Assume(cur_group != SENTINEL);
1521 Assume(prev_group != SENTINEL);
1522 if (entries[cur_group].deps.Overlaps(entries[prev_group].group)) {
1526 entries[cur_group].group |= entries[prev_group].group;
1527 entries[cur_group].deps |= entries[prev_group].deps;
1528 entries[cur_group].feerate += entries[prev_group].feerate;
1530 entries[entries[cur_group].first_tx].prev_tx = prev_group;
1532 entries[cur_group].first_tx = entries[prev_group].first_tx;
1534 prev_group = entries[prev_group].prev_group;
1535 entries[cur_group].prev_group = prev_group;
1538 DepGraphIndex preprev_group = entries[prev_group].prev_group;
1541 entries[next_group].prev_group = prev_group;
1542 entries[prev_group].prev_group = cur_group;
1543 entries[cur_group].prev_group = preprev_group;
1546 next_group = prev_group;
1547 prev_group = preprev_group;
1555 while (cur_group != SENTINEL) {
1561 *(linearization.begin() + (done++)) = cur_tx - 1;
1562 cur_tx = entries[cur_tx].prev_tx;
1563 }
while (cur_tx != NO_PREV_TX);
1566 *(linearization.end() - (++done)) = cur_tx - 1;
1567 cur_tx = entries[cur_tx].prev_tx;
1568 }
while (cur_tx != NO_PREV_TX);
1570 cur_group = entries[cur_group].prev_group;
1572 Assume(done == linearization.size());
1577template<
typename SetType>
1583 const auto len = linearization.size();
1591 SetType place_before = done & depgraph.
Ancestors(elem);
1594 while (place_before.Any()) {
1598 auto to_swap = linearization[len - 1 - (j - 1)];
1599 place_before.Reset(to_swap);
1600 linearization[len - 1 - (j--)] = to_swap;
1603 linearization[len - 1 - j] = elem;
#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.
bool empty() const noexcept
Test whether the contents of this deque is empty.
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.
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:
std::vector< TxData > m_tx_data
Information about each transaction (and chunks).
InsecureRandomContext m_rng
Internal RNG.
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.
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_rep to the chunk represented by top_rep,...
uint32_t TxIdx
Data type to represent indexing into m_tx_data.
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.
SpanningForestState(const DepGraph< SetType > &depgraph, uint64_t rng_seed) noexcept
Construct a spanning forest for the given DepGraph, with every transaction in its own chunk (not topo...
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.
std::vector< DepGraphIndex > GetLinearization() noexcept
Construct a topologically-valid linearization from the current forest state.
uint32_t DepIdx
Data type to represent indexing into m_dep_data.
SetType m_transaction_idxs
The set of all TxIdx's of transactions in the cluster indexing into m_tx_data.
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.
std::vector< FeeFrac > ChunkLinearization(const DepGraph< SetType > &depgraph, std::span< const DepGraphIndex > linearization) noexcept
Compute the feerates of the chunks of linearization.
std::tuple< std::vector< DepGraphIndex >, bool, uint64_t > Linearize(const DepGraph< SetType > &depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span< const DepGraphIndex > old_linearization={}) noexcept
Find or improve a linearization for a cluster.
void FixLinearization(const DepGraph< SetType > &depgraph, std::span< DepGraphIndex > linearization) noexcept
Make linearization topological, retaining its ordering where possible.
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::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...