Use relative tolerance for cycle-finder cost mismatch assertion#1240
Use relative tolerance for cycle-finder cost mismatch assertion#1240mlubin wants to merge 1 commit into
Conversation
The line "Cost mismatch after a move" assertion compares the realized cost change after `perform_moves` against the cycle finder's predicted `total_cycle_cost`. That predicted value is the sum of per-edge cost deltas read from a pre-computed candidate matrix; each delta is an O(1) approximation evaluated against the pre-move state, so chaining them around a cycle does not exactly equal the post-move recomputed cost. Empirically the drift is bounded by a small fraction of |cost_before|. The previous fixed `< 1.0` tolerance was fine at small problem cost magnitudes but under-budgeted that natural approximation slop once `cost_before` rose above ~100. This caused intermittent CI aborts in `level0_retail/retail_float_test_t.CVRPTW_Retail/18`. Switch to a relative tolerance with a 1.0 absolute floor, matching the pattern used elsewhere for similar cost-mismatch checks (`perform_cross`, `perform_two_opt`). Verified locally by running CVRPTW_Retail/18 in a loop 300 times under ASSERT_MODE. Before: ~1.7% per-iter abort rate. After: zero aborts. Closes NVIDIA#845 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Miles Lubin <mlubin@nvidia.com>
|
/ok to test 34fb29b |
📝 WalkthroughWalkthroughIn ChangesPost-move cost verification
🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/src/routing/local_search/local_search.cu`:
- Around line 320-321: The current cuopt_assert uses a one-sided check:
cuopt_assert((cost_after - cost_before) -
move_candidates.cycles.total_cycle_cost < ...), which allows large negative
residuals; change it to a symmetric magnitude check by taking the absolute value
of the residual: use abs((cost_after - cost_before) -
move_candidates.cycles.total_cycle_cost) < std::max(1., 0.01 *
std::abs(cost_before)) so the drift bound is enforced both directions for the
assertion in the cuopt_assert call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 8e6a84e9-f23a-4fe8-a0a3-5cad88776a58
📒 Files selected for processing (1)
cpp/src/routing/local_search/local_search.cu
| cuopt_assert((cost_after - cost_before) - move_candidates.cycles.total_cycle_cost < | ||
| std::max(1., 0.01 * std::abs(cost_before)), |
There was a problem hiding this comment.
Use a symmetric mismatch check for cycle-cost drift.
At Line 320, the check is one-sided; large negative residuals will always pass. If this is a drift bound, it should be magnitude-based.
Suggested fix
- cuopt_assert((cost_after - cost_before) - move_candidates.cycles.total_cycle_cost <
- std::max(1., 0.01 * std::abs(cost_before)),
+ const double cycle_cost_residual =
+ (cost_after - cost_before) - move_candidates.cycles.total_cycle_cost;
+ const double cycle_cost_tolerance = std::max(1.0, 0.01 * std::abs(cost_before));
+ cuopt_assert(std::abs(cycle_cost_residual) < cycle_cost_tolerance,
"Cost mismatch after a move");🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@cpp/src/routing/local_search/local_search.cu` around lines 320 - 321, The
current cuopt_assert uses a one-sided check: cuopt_assert((cost_after -
cost_before) - move_candidates.cycles.total_cycle_cost < ...), which allows
large negative residuals; change it to a symmetric magnitude check by taking the
absolute value of the residual: use abs((cost_after - cost_before) -
move_candidates.cycles.total_cycle_cost) < std::max(1., 0.01 *
std::abs(cost_before)) so the drift bound is enforced both directions for the
assertion in the cuopt_assert call.
(Fix to the flaky test discovered by Claude. Please validate correctness.)
The line "Cost mismatch after a move" assertion compares the realized cost change after
perform_movesagainst the cycle finder's predictedtotal_cycle_cost. That predicted value is the sum of per-edge cost deltas read from a pre-computed candidate matrix; each delta is an O(1) approximation evaluated against the pre-move state, so chaining them around a cycle does not exactly equal the post-move recomputed cost. Empirically the drift is bounded by a small fraction of |cost_before|.The previous fixed
< 1.0tolerance was fine at small problem cost magnitudes but under-budgeted that natural approximation slop oncecost_beforerose above ~100. This caused intermittent CI aborts inlevel0_retail/retail_float_test_t.CVRPTW_Retail/18.Switch to a relative tolerance with a 1.0 absolute floor, matching the pattern used elsewhere for similar cost-mismatch checks (
perform_cross,perform_two_opt).Verified locally by running CVRPTW_Retail/18 in a loop 300 times under ASSERT_MODE. Before: ~1.7% per-iter abort rate. After: zero aborts.
Closes #845