mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
clusterlin: add GetConnectedComponent
This abstracts out the finding of the connected component that includes a given element from FindConnectedComponent (which just finds any connected component). Use this in the txgraph fuzz test, which was effectively reimplementing this logic. At the same time, improve its performance by replacing a vector with a set.
This commit is contained in:
parent
c7d5dcaa61
commit
a52b53926b
3 changed files with 44 additions and 28 deletions
|
@ -250,10 +250,8 @@ public:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/** Find some connected component within the subset "todo" of this graph.
|
||||
*
|
||||
* Specifically, this finds the connected component which contains the first transaction of
|
||||
* todo (if any).
|
||||
/** Get the connected component within the subset "todo" that contains tx (which must be in
|
||||
* todo).
|
||||
*
|
||||
* Two transactions are considered connected if they are both in `todo`, and one is an ancestor
|
||||
* of the other in the entire graph (so not just within `todo`), or transitively there is a
|
||||
|
@ -262,10 +260,11 @@ public:
|
|||
*
|
||||
* Complexity: O(ret.Count()).
|
||||
*/
|
||||
SetType FindConnectedComponent(const SetType& todo) const noexcept
|
||||
SetType GetConnectedComponent(const SetType& todo, DepGraphIndex tx) const noexcept
|
||||
{
|
||||
if (todo.None()) return todo;
|
||||
auto to_add = SetType::Singleton(todo.First());
|
||||
Assume(todo[tx]);
|
||||
Assume(todo.IsSubsetOf(m_used));
|
||||
auto to_add = SetType::Singleton(tx);
|
||||
SetType ret;
|
||||
do {
|
||||
SetType old = ret;
|
||||
|
@ -279,6 +278,19 @@ public:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/** Find some connected component within the subset "todo" of this graph.
|
||||
*
|
||||
* Specifically, this finds the connected component which contains the first transaction of
|
||||
* todo (if any).
|
||||
*
|
||||
* Complexity: O(ret.Count()).
|
||||
*/
|
||||
SetType FindConnectedComponent(const SetType& todo) const noexcept
|
||||
{
|
||||
if (todo.None()) return todo;
|
||||
return GetConnectedComponent(todo, todo.First());
|
||||
}
|
||||
|
||||
/** Determine if a subset is connected.
|
||||
*
|
||||
* Complexity: O(subset.Count()).
|
||||
|
|
|
@ -446,19 +446,36 @@ FUZZ_TARGET(clusterlin_components)
|
|||
// Construct a depgraph.
|
||||
SpanReader reader(buffer);
|
||||
DepGraph<TestBitSet> depgraph;
|
||||
std::vector<DepGraphIndex> linearization;
|
||||
try {
|
||||
reader >> Using<DepGraphFormatter>(depgraph);
|
||||
} catch (const std::ios_base::failure&) {}
|
||||
|
||||
TestBitSet todo = depgraph.Positions();
|
||||
while (todo.Any()) {
|
||||
// Find a connected component inside todo.
|
||||
auto component = depgraph.FindConnectedComponent(todo);
|
||||
// Pick a transaction in todo, or nothing.
|
||||
std::optional<DepGraphIndex> picked;
|
||||
{
|
||||
uint64_t picked_num{0};
|
||||
try {
|
||||
reader >> VARINT(picked_num);
|
||||
} catch (const std::ios_base::failure&) {}
|
||||
if (picked_num < todo.Size() && todo[picked_num]) {
|
||||
picked = picked_num;
|
||||
}
|
||||
}
|
||||
|
||||
// Find a connected component inside todo, including picked if any.
|
||||
auto component = picked ? depgraph.GetConnectedComponent(todo, *picked)
|
||||
: depgraph.FindConnectedComponent(todo);
|
||||
|
||||
// The component must be a subset of todo and non-empty.
|
||||
assert(component.IsSubsetOf(todo));
|
||||
assert(component.Any());
|
||||
|
||||
// If picked was provided, the component must include it.
|
||||
if (picked) assert(component[*picked]);
|
||||
|
||||
// If todo is the entire graph, and the entire graph is connected, then the component must
|
||||
// be the entire graph.
|
||||
if (todo == depgraph.Positions()) {
|
||||
|
|
|
@ -561,36 +561,23 @@ FUZZ_TARGET(txgraph)
|
|||
std::shuffle(refs.begin(), refs.end(), rng);
|
||||
// Invoke the real function.
|
||||
auto result = real->CountDistinctClusters(refs, use_main);
|
||||
// Build a vector with representatives of the clusters the Refs occur in in the
|
||||
// Build a set with representatives of the clusters the Refs occur in in the
|
||||
// simulated graph. For each, remember the lowest-index transaction SimPos in the
|
||||
// cluster.
|
||||
std::vector<DepGraphIndex> sim_reps;
|
||||
SimTxGraph::SetType sim_reps;
|
||||
for (auto ref : refs) {
|
||||
// Skip Refs that do not occur in the simulated graph.
|
||||
auto simpos = sel_sim.Find(ref);
|
||||
if (simpos == SimTxGraph::MISSING) continue;
|
||||
// Start with component equal to just the Ref's SimPos.
|
||||
auto component = SimTxGraph::SetType::Singleton(simpos);
|
||||
// Keep adding ancestors/descendants of all elements in component until it no
|
||||
// longer changes.
|
||||
while (true) {
|
||||
auto old_component = component;
|
||||
for (auto i : component) {
|
||||
component |= sel_sim.graph.Ancestors(i);
|
||||
component |= sel_sim.graph.Descendants(i);
|
||||
}
|
||||
if (component == old_component) break;
|
||||
}
|
||||
// Find the component that includes ref.
|
||||
auto component = sel_sim.graph.GetConnectedComponent(sel_sim.graph.Positions(), simpos);
|
||||
// Remember the lowest-index SimPos in component, as a representative for it.
|
||||
assert(component.Any());
|
||||
sim_reps.push_back(component.First());
|
||||
sim_reps.Set(component.First());
|
||||
}
|
||||
// Remove duplicates from sim_reps.
|
||||
std::sort(sim_reps.begin(), sim_reps.end());
|
||||
sim_reps.erase(std::unique(sim_reps.begin(), sim_reps.end()), sim_reps.end());
|
||||
// Compare the number of deduplicated representatives with the value returned by
|
||||
// the real function.
|
||||
assert(result == sim_reps.size());
|
||||
assert(result == sim_reps.Count());
|
||||
break;
|
||||
} else if (command-- == 0) {
|
||||
// DoWork.
|
||||
|
|
Loading…
Add table
Reference in a new issue