Possibly all the ways to get loop-finding in graphs wrong
chiark.greenend.org.uk
chiark.greenend.org.uk
[0]:https://en.wikipedia.org/wiki/Disjoint-set_data_structure
[0] https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoi...
I always thought it's a linked list algo
Several of the suggested algorithms were in fact implemented in the various Cuckoo Cycle solvers [2]. But by maintaining directed paths, my union-find based algorithm did identify the entire cycle and not just the cycle completing edge [1] (implemented in [3]).
This algorithm suffers from three problems though. One, it only finds one among a set of interconnected cycles. Second, it's rather slow, being latency bound by the random memory accesses. Third, it uses much more memory than needed.
So repeatedly trimming edges with only one endpoint is a much faster approach. And for the random graphs that the PoW generates, it can be done using only 1 bit per edge to record if it's been trimmed.
Once sufficiently trimmed, a loop tracing algorithm (like [4] for the Cuckatoo Cycle variant) can find all remaining (simple) cycles.
[1] https://www.semanticscholar.org/paper/Cuckoo-Cycle%3A-A-Memo...
[2] https://github.com/tromp/cuckoo
[3] https://github.com/tromp/cuckoo/blob/master/src/cuckoo/cycle...
[4] https://github.com/tromp/cuckoo/blob/master/src/cuckatoo/gra...
* can be pseudo randomly generated from a seed (usually the hash of a partial blockchain header)
* have a known optimal solution method with a (nearly) constant running time that's at most about one second (for progress freeness this should be a small fraction of the target block time)
NP-hard problems rarely satisfy both these constraints. Finding fixed length cycles in random (bipartite) graphs with billions of edges does.
For planar graphs on the surface of a torus, like they faced here, I just ended up adding extra images of the central unit cell, and then removing the excess. Not elegant (lots of weird corner cases) but convenient for visualisation.
https://depth-first.com/articles/2020/08/31/a-smallest-set-o...
https://daylight.com/dayhtml/doc/theory/theory.smarts.html
BTW, there is a very clever algorithm for finding SSSR
What's the graph-theoretical approach? Does it have nicer characteristics?
It sounds horribly slow, but isn't because the loop finding process for one edge can mark all edges it traverses as either being on the same loop, or not having a loop, for the orientation its checking. These edges can be skipped henceforth.
This does not find all loops, only the smallest disjoint loops (as every edge is at most part of two disjoint loops). But basically results in a similar planar "face" partition the author describes.
Its not clear to me whether my approach does not work (perhaps the angle compares fail on a torus? I've never had to deal with torii), or simply isn't suited because it misses some loops, but I thought I'd share it anyway :-)
I may be missing a detail, but it seems to fail on a graph consisting of a loop with some extra edges branching off the loop toward its interior and some edges branching off toward the exterior. The left hand walk hits a dead end in one branch, and the right hand walk dead ends in the other, no matter where on the loop you start (except for some special cases).
Edit: strengthening the proposed counterexample
I think this is roughly the counterexample the person above was suggesting.
It's an edge case that should be handled, but does not prevent the general algo from working.
However, indeed it remains true that it does not find all loops, only the smallest set of loops that cover all edges.
you'd get the same pitfall of torus topology with 2 perpendicular loops
If you don‘t need to be efficient, any problem is relatively easy to solve.
> When in doubt, use brute force. —KLT
---
EDIT: looks like Okasaki has a linear-time functional; I'm pragmatic enough that 2 passes are (even small constant passes would be) fine for me — my graphs are all tiny enough that I'm not about to store them on tape.
EDIT2: my bad, not Okasaki himself, King & Launchbury: https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&d...
scc' :: Graph -> Forest Vertex
scc' g = dfs g (reverse (postOrd (transposeG g)))
(but their sol'n requires laziness to avoid generating an infinite intermediate; has anyone done it linearly, functionally, and eagerly?) StronglyConnectedVertices(Vertex source) => ReachableVertices(source).Intersect(ReverseReachableVertices(source))
The methods ReachableVertices and ReverseReachableVertices are effectively depth-first searches on the graph.The challenge - in terms of performance - is actually not finding a single SCC but returning the full set of potentially thousands SCCs in large networks. I originally implemented an iterative (imperative) version of Gabow's "Path-Based" algorithm but it was too slow on continent-sized datasets. We did some experimentation with a parallel variant of Tarjan which didn't improve things much.
Eventually I settled for something "good enough" - randomly pick a vertex, calculate the SCC with the above code, return it if it's large enough (>1k vertices) otherwise filter it out, keep going until I've accounted for >90% of the graph. The remaining <10% gets filtered out. That's basically imperative (using a while loop) but could probably be functionalised.
-----------------------------------------------------
EDIT I've taken a better look at the linked paper and what I wrote is definitely not an answer to your question. But I'll leave it in case anyone's interested.
If the graph is directed, do an SCC decomposition in linear time using a graph library and then any SCC with size more than one has at least a loop, trivially extracted by following any edges in the SCC.
If the graph is undirected, compute a spanning tree in linear time using a graph library and then any edge outside the tree forms a loop, again trivially extractable from the edge and the paths from its endpoints to their least common ancestor in the tree.
Since those algorithms are already asymptotically optimal, it's just an engineering problem of finding the solution with the best constant factor given the precise data structures and goal in question.
However in the article it’s actually a graph being modified. If you don’t want to run a full dfs every time, there are better ways. This problem is called “online cycle detection” and you can google some other algorithms.
> Spews out computer science jargon that 99% of the world's population wouldn't even recognise, let alone understand.
Hmm.