Repository navigation
fix: DGraph.nc no longer loops forever; one components algorithm - #52
Merged
Merged
Conversation
… one algorithm For many directed graphs, the smallest being the 4-cycle 0->2->1->3->0, DGraph._graphcolor never returned: it merged labels with 'while vlabel in merge: vlabel = merge[vlabel]', and the merge map could contain a cycle. nc, component(), samecomponent() and plot() all ask for the components, so all of them hung. It was the same in 0.6.5, and a random 100-vertex digraph hangs. The graph now has one algorithm, a single O(V+E) traversal that follows each edge in either direction, so the components of a directed graph are weakly connected, which is what its tests and downstream code assume and what the undirected algorithm already did. Components are numbered from 0 by the first vertex of each, in the order the vertices were added, for both kinds. Also: - the components were found again by every nc, component() or samecomponent() once the graph had ever changed, because the graph's own flag was never cleared; it is now, so a call after no change is free (plot() asked for each component in turn) - Vertex.label finds the components when it is read, instead of being None until something else had asked; the tests had to prime it with g.nc - a removed vertex has no label - samecomponent() documented that in a directed graph 'same component' implies a path, and in an undirected graph does not, which is backwards: it now says what a weak component is, with the a -> c <- b example Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 59 |
| Duplication | 0 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #52 +/- ##
==========================================
+ Coverage 95.37% 95.88% +0.50%
==========================================
Files 3 3
Lines 1277 1238 -39
==========================================
- Hits 1218 1187 -31
+ Misses 59 51 -8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DGraph.ncloops forever for many directed graphs, and so does everything that asks for the components:component(),samecomponent()andplot(). This fixes it.The bug
DGraph._graphcolormerged component labels withand the
mergemap can contain a cycle, so it never ends. The smallest case is a plain directed 4-cycle:A random 100-vertex, 300-edge digraph hangs too, and so does an acyclic one. It is the same on 0.6.5. The existing directed tests use tiny graphs that happen not to trigger it. I found it by timing
plot()on a larger directed graph.The fix
One algorithm, on
Graph: a single O(V+E) traversal that follows each edge in either direction, replacing the two separate ones inUGraphandDGraph.Also fixed in the same code
nc,component()andsamecomponent()re-colored the whole graph.plot()asked for each component in turn. Now a call after no change is free.Vertex.labelwasNoneuntil something else had asked for the components (the tests had to prime it withg.nc). Reading it now finds them.samecomponent()docstring was backwards: it said that for a directed graph "same component" implies a path and for an undirected graph it does not. It now says what a weak component is, witha -> c <- bas the example.Tests
tests/test_components.py(36, both kinds), with a timeout guard so a hang fails rather than freezes the run, and expectations from hand-written cases or a union-find in the test:component()order, 0 tonc-1a -> c <- b), opposite edges, andDGraphagrees withUGraphon the same edgesOn
main, the 4-cycle tests hang and thelabeltests fail.🤖 Generated with Claude Code