Skip to content

Fix degenerate ball-ball collision roots - #354

Merged
ekiefl merged 3 commits into
ekiefl:mainfrom
martin0359:martin0359/fix-chain2ball-degenerate-roots
Nov 8, 2026
Merged

ekiefl merged 3 commits into
ekiefl:mainfrom
martin0359:martin0359/fix-chain2ball-degenerate-roots

Conversation

@martin0359

@martin0359 martin0359 commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This fixes degenerate ball-ball collision detection cases where the collision polynomial is not actually quartic. I found this while running a chain2ball-style regression: two balls can have zero relative acceleration, producing a lower-degree distance equation. The 2D detector still passed that equation to quartic.solve(...), which now raises when the leading coefficient is zero. Older behavior could also turn the degenerate case into a false t = 0 collision.

The fix keeps the quartic solver contract intact and handles the degenerate polynomial at the collision-detection call sites. When the quartic term is zero, the detector dispatches to the quadratic solver. Exact-contact cases are only reported as t = 0 collisions if the balls are closing; tangent non-closing cases return inf.

Changes

  • Dispatch degenerate generic/3D ball-ball distance polynomials to quadratic.solve(...) instead of quartic.solve(...).
  • Dispatch degenerate 2D ball-ball distance polynomials to quadratic.solve(...).
  • Avoid false t = 0 events for exact tangent balls that are stationary relative to each other or moving apart.
  • Add regression coverage for no-collision chain-style degeneracy, finite lower-degree roots, and exact tangent closing/non-closing behavior across 2D and 3D detector paths.

Additional non-degenerate path check

To make sure the fix does not change ordinary ball-ball detection, I also ran a local randomized check over 500 non-degenerate rolling/sliding 2D cases where a != 0. For each sample, I compared the patched detector result against the pre-existing quartic path (quartic.solve(a, b, c, d, e) followed by get_real_positive_smallest_root). The maximum observed absolute difference was 0.0, so the ordinary quartic path was unchanged in that sample set.

I also compared constructed degenerate and near-degenerate 2D cases against analytic roots to check the lower-degree branch directly.

Validation

  • uv run ruff check pooltool/evolution/event_based/detect/ball_ball.py tests/evolution/event_based/test_ball_ball.py
  • uv run pytest tests/evolution/event_based/test_ball_ball.py -q
  • uv run pytest tests/evolution/event_based -q
  • uv run pytest -q

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
Finishing Touches

🧪 Generate unit tests (beta)

  • Create PR with unit tests
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@ekiefl

ekiefl commented Sep 6, 2026

Copy link
Copy Markdown
Owner

@martin0359 Hey Martin, can you tell me a little more about this PR? What motivated it? Cheers.

@martin0359

Copy link
Copy Markdown
Contributor Author

@martin0359 Hey Martin, can you tell me a little more about this PR? What motivated it? Cheers.

Thank you for your reply. I am developing a Chinese 8-ball billiard physics engine using WASM. During this process, I used some YOLO-processed event video materials and your engine to align and calibrate, and then find this issue.

@ekiefl
ekiefl marked this pull request as ready for review November 8, 2026 20:30
@ekiefl
ekiefl self-requested a review as a code owner November 8, 2026 20:30
martin0359 and others added 2 commits November 8, 2026 12:31
Each root of the contact equation is a time the balls are exactly 2R
apart, which happens both when they come together and when they come
apart. get_smallest_approaching_root keeps only the earliest real,
non-negative root with dot(r, v) < 0, and both ball-ball detectors use
it. This replaces the exact-contact special cases, which only covered
the degenerate quadratic branch.
@ekiefl
ekiefl force-pushed the martin0359/fix-chain2ball-degenerate-roots branch from 63b7aa3 to 40afd0f Compare November 8, 2026 20:59
@ekiefl

ekiefl commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Thank you for spotting these issues and proposing a fix. I built on your changes and I'm going to merge. Thanks!

@codecov

codecov Bot commented Nov 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 16.12903% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.24%. Comparing base (7c7d0e2) to head (c1051c5).

Files with missing lines Patch % Lines
pooltool/evolution/event_based/detect/ball_ball.py 16.12% 26 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #354      +/-   ##
==========================================
- Coverage   50.34%   50.24%   -0.10%     
==========================================
  Files         166      166              
  Lines       11461    11489      +28     
==========================================
+ Hits         5770     5773       +3     
- Misses       5691     5716      +25     
Flag Coverage Δ
service 50.24% <16.12%> (-0.10%) ⬇️
service-no-ani 59.69% <16.12%> (-0.19%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ekiefl
ekiefl merged commit 4cf43a8 into ekiefl:main Nov 8, 2026
9 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants