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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find some connected component within the subset "todo" of this graph.
|
/** Get the connected component within the subset "todo" that contains tx (which must be in
|
||||||
*
|
* todo).
|
||||||
* Specifically, this finds the connected component which contains the first transaction of
|
|
||||||
* todo (if any).
|
|
||||||
*
|
*
|
||||||
* Two transactions are considered connected if they are both in `todo`, and one is an ancestor
|
* 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
|
* 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()).
|
* 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;
|
Assume(todo[tx]);
|
||||||
auto to_add = SetType::Singleton(todo.First());
|
Assume(todo.IsSubsetOf(m_used));
|
||||||
|
auto to_add = SetType::Singleton(tx);
|
||||||
SetType ret;
|
SetType ret;
|
||||||
do {
|
do {
|
||||||
SetType old = ret;
|
SetType old = ret;
|
||||||
|
@ -279,6 +278,19 @@ public:
|
||||||
return ret;
|
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.
|
/** Determine if a subset is connected.
|
||||||
*
|
*
|
||||||
* Complexity: O(subset.Count()).
|
* Complexity: O(subset.Count()).
|
||||||
|
|
|
@ -446,19 +446,36 @@ FUZZ_TARGET(clusterlin_components)
|
||||||
// Construct a depgraph.
|
// Construct a depgraph.
|
||||||
SpanReader reader(buffer);
|
SpanReader reader(buffer);
|
||||||
DepGraph<TestBitSet> depgraph;
|
DepGraph<TestBitSet> depgraph;
|
||||||
|
std::vector<DepGraphIndex> linearization;
|
||||||
try {
|
try {
|
||||||
reader >> Using<DepGraphFormatter>(depgraph);
|
reader >> Using<DepGraphFormatter>(depgraph);
|
||||||
} catch (const std::ios_base::failure&) {}
|
} catch (const std::ios_base::failure&) {}
|
||||||
|
|
||||||
TestBitSet todo = depgraph.Positions();
|
TestBitSet todo = depgraph.Positions();
|
||||||
while (todo.Any()) {
|
while (todo.Any()) {
|
||||||
// Find a connected component inside todo.
|
// Pick a transaction in todo, or nothing.
|
||||||
auto component = depgraph.FindConnectedComponent(todo);
|
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.
|
// The component must be a subset of todo and non-empty.
|
||||||
assert(component.IsSubsetOf(todo));
|
assert(component.IsSubsetOf(todo));
|
||||||
assert(component.Any());
|
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
|
// If todo is the entire graph, and the entire graph is connected, then the component must
|
||||||
// be the entire graph.
|
// be the entire graph.
|
||||||
if (todo == depgraph.Positions()) {
|
if (todo == depgraph.Positions()) {
|
||||||
|
|
|
@ -561,36 +561,23 @@ FUZZ_TARGET(txgraph)
|
||||||
std::shuffle(refs.begin(), refs.end(), rng);
|
std::shuffle(refs.begin(), refs.end(), rng);
|
||||||
// Invoke the real function.
|
// Invoke the real function.
|
||||||
auto result = real->CountDistinctClusters(refs, use_main);
|
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
|
// simulated graph. For each, remember the lowest-index transaction SimPos in the
|
||||||
// cluster.
|
// cluster.
|
||||||
std::vector<DepGraphIndex> sim_reps;
|
SimTxGraph::SetType sim_reps;
|
||||||
for (auto ref : refs) {
|
for (auto ref : refs) {
|
||||||
// Skip Refs that do not occur in the simulated graph.
|
// Skip Refs that do not occur in the simulated graph.
|
||||||
auto simpos = sel_sim.Find(ref);
|
auto simpos = sel_sim.Find(ref);
|
||||||
if (simpos == SimTxGraph::MISSING) continue;
|
if (simpos == SimTxGraph::MISSING) continue;
|
||||||
// Start with component equal to just the Ref's SimPos.
|
// Find the component that includes ref.
|
||||||
auto component = SimTxGraph::SetType::Singleton(simpos);
|
auto component = sel_sim.graph.GetConnectedComponent(sel_sim.graph.Positions(), 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;
|
|
||||||
}
|
|
||||||
// Remember the lowest-index SimPos in component, as a representative for it.
|
// Remember the lowest-index SimPos in component, as a representative for it.
|
||||||
assert(component.Any());
|
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
|
// Compare the number of deduplicated representatives with the value returned by
|
||||||
// the real function.
|
// the real function.
|
||||||
assert(result == sim_reps.size());
|
assert(result == sim_reps.Count());
|
||||||
break;
|
break;
|
||||||
} else if (command-- == 0) {
|
} else if (command-- == 0) {
|
||||||
// DoWork.
|
// DoWork.
|
||||||
|
|
Loading…
Add table
Reference in a new issue