BUG: fix an infinite loop in itk::VoronoiDiagram2DGenerator#5400
BUG: fix an infinite loop in itk::VoronoiDiagram2DGenerator#5400ILoveGoulash wants to merge 2 commits intoInsightSoftwareConsortium:mainfrom
Conversation
There was a problem hiding this comment.
Thank you for contributing a pull request! 🙏
Welcome to the ITK community! 🤗👋☀️
We are glad you are here and appreciate your contribution. Please keep in mind our community participation guidelines. 📜
More support and guidance on the contribution process can be found in our contributing guide. 📖
This is an automatic message. Allow for time for the ITK community to be able to read the pull request and comment
on it.
|
Don't know if you want a regression test, and if your framework can handle "infinite looping" type failures. |
|
A regression test is advantageous. I don't think we have an explicit support for infinite looping, but such a test would fail via timeout. |
|
Added the original case by doing "monkey see monkey do", but it looks like I can't build locally due to IPFS + work firewall or something. |
f5ff22b to
62457de
Compare
dzenanz
left a comment
There was a problem hiding this comment.
OK, I can reproduce locally an infinite loop with this test.
|
Nah, the full "http://..." link is probably what triggers it, GitHub prettifies it on display. |
62457de to
288b65e
Compare
Modules/Segmentation/Voronoi/include/itkVoronoiDiagram2DGenerator.hxx
Outdated
Show resolved
Hide resolved
|
@ILoveGoulash Thank you for your contribution. There are just a few final actions that need to be finalized so that we can incorporate this into the main tree. |
288b65e to
380c33d
Compare
|
Should be okay now. |
8f868e4 to
c6ccef6
Compare
|
@ILoveGoulash I rebased and removed the merge conflict, then updated the commit message for the regression test to be more descriptive. |
|
Thanks! |
c6ccef6 to
cec88e2
Compare
|
Ping. |
The loop exit condition was present in the code, but never wired and removed via InsightSoftwareConsortium@cd97879 Fixes InsightSoftwareConsortium#4386
Tests and resolves InsightSoftwareConsortium#4386 where specific values caused deadlocks.
4aa2b26 to
ddccb03
Compare
| itkVoronoiDiagram2DInfiniteLoopTest(int argc, char * argv[]) | ||
| { | ||
| if (argc != 1) | ||
| { | ||
| std::cerr << "Takes no parameters, but " << argc << "parameters given" << std::endl; |
There was a problem hiding this comment.
When the test has no parameters, preferably make it a GoogleTest. GoogleTest unit tests are typically more "to the point", avoiding unnecessary verbosity.
| EdgeInfo back = curr; | ||
| while (!(rawEdges[i].empty())) | ||
| auto maxStop = rawEdges[i].size(); | ||
| while (!(rawEdges[i].empty()) && (maxStop != 0)) |
There was a problem hiding this comment.
Do I understand correctly that the check !(rawEdges[i].empty()) is redundant now? I mean, could it just say:
while ( maxStop > 0 )If so, I would prefer such a simplification.
There was a problem hiding this comment.
Couldn't simply be a for loop?
for ( auto maxStop = rawEdges[i].size(); maxStop != 0; --maxStop ) Maybe then rename maxStop to j:
for ( auto j = rawEdges[i].size(); j != 0; --j ) There was a problem hiding this comment.
@N-Dekker I've looked into this some more. The problem is more difficult than the requested change you proposed. I think the issue is that we are running into a corner case of the algorithm that is not handled.
This PR adds a test that induces an infinite loop. The initially requested change breaks the infinite loop but changes the algorithm's behavior. (other test starts failing).
I haven't figured out what needs to be done, but it likely requires careful consideration of the implemented algorithm and more careful identification of corner cases.
The crux of the problem is removing items from the list for processing, then adding them back to the list if none of the described cases are met (i.e. an infinite loop occurs).
Add stall detection to the edge-assembly loop that builds Voronoi cell boundaries. The loop pops edges from a deque and tries to attach them to a growing chain; unattachable edges are pushed back for retry. With certain degenerate seed configurations (ITK issue InsightSoftwareConsortium#4386), some edges can never attach, causing the loop to run forever. The fix tracks a stall counter that is reset whenever an edge successfully attaches (since new attachments change the chain endpoints and may make previously unattachable edges attachable). When a full pass through the deque makes no progress, the loop terminates. This improves on the approach in PR InsightSoftwareConsortium#5400, which used a simple countdown that could terminate too early — causing itkVoronoiPartitioningImageFilterTest2 to fail because edges that would have been attachable in a subsequent pass were prematurely dropped. A regression test using the seed configuration from issue InsightSoftwareConsortium#4386 is included.
Fix an infinite loop in ConstructDiagram() that occurs with certain degenerate seed configurations (ITK issue InsightSoftwareConsortium#4386, supersedes PR InsightSoftwareConsortium#5400). Root cause: Fortune's algorithm produces near-zero-length edges when boundary intersection points coincide within floating-point tolerance but receive different vertex IDs. These edges cannot attach to the growing cell boundary chain because: 1. Their vertex IDs don't match any chain endpoint. 2. The chain may already be closed (front == back). 3. Boundary-bridging logic doesn't apply when chain endpoints are interior (not on the domain boundary). The fix has three parts: 1. Explicit degenerate edge detection: before attempting attachment, each edge is checked with the existing differentPoint() tolerance (DIFF_TOLERENCE = 0.001). Edges whose endpoints are geometrically identical are discarded immediately — they carry no geometric information and are floating-point artifacts. 2. Stall detection: a counter tracks assembly progress and resets whenever an edge attaches (since new attachments change the chain endpoints and may make previously unattachable edges attachable). When a full pass through the deque makes no progress, the loop terminates. This improves on PR InsightSoftwareConsortium#5400's simple countdown which terminated too early, breaking itkVoronoiPartitioningImageFilterTest2. 3. Exception on unexpected residuals: after assembly, if any non-degenerate edges remain, itkExceptionMacro fires to ensure unexpected geometric configurations are reported rather than silently producing incomplete diagrams. A regression test using the seed configuration from issue InsightSoftwareConsortium#4386 verifies termination and validates all cell boundaries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix an infinite loop in ConstructDiagram() that occurs with certain degenerate seed configurations (ITK issue InsightSoftwareConsortium#4386, supersedes PR InsightSoftwareConsortium#5400). Root cause: Fortune's algorithm produces near-zero-length edges when boundary intersection points coincide within floating-point tolerance but receive different vertex IDs. These edges cannot attach to the growing cell boundary chain because: 1. Their vertex IDs don't match any chain endpoint. 2. The chain may already be closed (front == back). 3. Boundary-bridging logic doesn't apply when chain endpoints are interior (not on the domain boundary). The fix has three parts: 1. Explicit degenerate edge detection: before attempting attachment, each edge is checked with the existing differentPoint() tolerance (DIFF_TOLERENCE = 0.001). Edges whose endpoints are geometrically identical are discarded immediately — they carry no geometric information and are floating-point artifacts. 2. Stall detection: a counter tracks assembly progress and resets whenever an edge attaches (since new attachments change the chain endpoints and may make previously unattachable edges attachable). When a full pass through the deque makes no progress, the loop terminates. This improves on PR InsightSoftwareConsortium#5400's simple countdown which terminated too early, breaking itkVoronoiPartitioningImageFilterTest2. 3. Exception on unexpected residuals: after assembly, if any non-degenerate edges remain, itkExceptionMacro fires to ensure unexpected geometric configurations are reported rather than silently producing incomplete diagrams. A regression test using the seed configuration from issue InsightSoftwareConsortium#4386 verifies termination and validates all cell boundaries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The loop exit condition was present in the code, but never wired and removed via cd97879
PR Checklist
Refer to the ITK Software Guide for
further development details if necessary.