Skip to content

fix(crane_geometry): Intervalの境界一致処理(erase/append)を修正 - #1379

Merged
HansRobo merged 2 commits into
developfrom
fix/geometry-interval-erase-boundary
Sep 17, 2026
Merged

HansRobo merged 2 commits into
developfrom
fix/geometry-interval-erase-boundary

Conversation

@HansRobo

@HansRobo HansRobo commented May 30, 2026 •

Copy link
Copy Markdown
Member

概要

crane_geometry の Interval クラスで、区間の境界が厳密に一致するケースを取りこぼす同種のバグが erase(区間減算)と append(区間追加のマージ判定)の両方にあったため、両方を修正しました。

問題

interval.hpp の境界判定が厳密不等号(< / >)のみで行われていたため、ある区間の境界値が別の区間・別の erase 範囲の境界値と厳密に一致する場合に判定を取りこぼし、不正な区間を生成していました。

再現例(erase 側、単一区間・単一 erase で再現する最小ケース):

append(1, 19);
erase(1, 7);   // 期待: 幅 12([7,19])だが、修正前は 18(変化なし)のまま

erase(1, 7) の下限 1 が既存区間の下限 1 と厳密に一致するため、「下限修正」の判定 (lowers[i] > lower) が 1 > 1 = false となり、区間が全く縮まりませんでした。2つの区間が絡む必要はなく、単一区間への単一 erase だけで発生します。

同種の問題は append のマージ判定 (uppers[i - 1] > lowers[i]) にもあり、境界がちょうど接する2区間が本来1区間にマージされるべき場面でマージされずに残ってしまいます:

append(1, 8);
append(8, 19);  // 境界 8 で接する2区間 → 本来 [1, 19] の1区間にマージされるべき
// 修正前: getLargestInterval() は [8, 19](幅11)を返し、[1, 19](幅18)にならない

この区間計算は world_model_wrapper.cpp の getLargestGoalAngleRangeFromPoint(シュートコース角度計算)で使われています。ただし、この境界一致は連続的に変化する角度値どうしの厳密な浮動小数点一致を要求するため、実際の試合データで発生する確率は極めて低く、実際に誤ったシュート角度選択を引き起こしたという具体的な証拠(リプレイ等)はありません。ソースコード監査で見つかった潜在的な正当性バグという位置づけです。

原因

  • erase の境界条件で <= を使うべき箇所が < になっており、境界一致時に区間が正しく縮められなかった。
  • append のマージ判定も同様に >= を使うべき箇所が > になっており、境界がちょうど接する区間がマージされなかった。

(過去のドラフトでは「個別 sort によるペア崩れ」を原因の一つとして挙げていましたが、複数ケースを手計算で検証した結果、ペア対応は sort 後も保たれており、これは実際の原因ではありませんでした。真の原因は上記の境界判定の厳密不等号のみです。)

修正内容

erase

区間減算として正しく再実装しました。消去区間 [L, U] を各既存区間 [lo, hi] から引く際、以下の場合分けを行います。

  • U <= lo || L >= hi: 重なりなし(境界一致を含む)→ 区間はそのまま残す
  • L <= lo && U >= hi: 完全に覆われる → 区間を削除
  • L > lo && U < hi: 中抜き → [lo, L] と [U, hi] の 2 区間に分割
  • L <= lo: 下端を縮める → [U, hi]
  • それ以外(lo < L, hi <= U): 上端を縮める → [lo, L]

結果は新しい区間リストとして再構築することで、uppers / lowers のペア対応を常に保持します。

append

マージ判定を uppers[i - 1] > lowers[i] から uppers[i - 1] >= lowers[i] に変更し、境界が接する区間も連続区間としてマージされるようにしました。

検証

  • colcon build --packages-select crane_geometry でコンパイルが正常に完了することを確認。
  • colcon test --packages-select crane_geometry を実行し、既存テストに加えて以下の回帰テストを追加のうえ全テスト成功を確認:
    • AppendTouchingBoundaryMerges: 境界が接する2区間の append が1区間にマージされること
    • EraseExactBoundaryMatchShrinksInterval: 単一区間への単一 erase で境界厳密一致時も正しく縮まること(上記の最小再現例)

レビュー観点

  • erase の場合分け(境界一致での <= の使用、中抜き分割、端の縮め)の網羅性と正当性。
  • append の境界一致マージ (>=) が既存の重複マージ処理を退行させていないこと。
  • uppers / lowers をペアとして再構築することで対応が崩れないこと。

本PRはソースコード監査ワークフローで検出されたバグに対する修正です。

@HansRobo HansRobo changed the title fix(crane_geometry): Interval::eraseの境界一致ケース取りこぼしを修正 fix(crane_geometry): Intervalの境界一致処理(erase/append)を修正 Sep 17, 2026
erase() の境界一致修正と同じ厳密不等号の問題が append() の重複判定にも
残っており、境界がちょうど接する2区間(例: [1,8]と[8,19])がマージされず
2区間のまま残ってしまう状態だった。マージ判定を `>` から `>=` に変更し、
境界一致マージのテスト(AppendTouchingBoundaryMerges)を追加した。

また、erase() 側のバグ再現に単一区間・単一eraseで十分であることを示す
最小ケースのテスト(EraseExactBoundaryMatchShrinksInterval)も追加した。
@HansRobo
HansRobo force-pushed the fix/geometry-interval-erase-boundary branch from 99e6041 to 148e18e Compare September 17, 2026 10:00
@HansRobo
HansRobo merged commit 0946f52 into develop Sep 17, 2026
8 checks passed
@HansRobo
HansRobo deleted the fix/geometry-interval-erase-boundary branch September 17, 2026 10:01
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.

1 participant