VV: DBSCAN Full V&V Complete - #1702
Conversation
ec3685f to
b824390
Compare
fb5177c to
0c9819b
Compare
Review changes for PR BlueQuartzSoftware#1702. Algorithm: * Guard both HyperGridBitMap constructors against all-NaN bounds. When every point is masked off the bounds stay quiet_NaN and were then cast to usize to compute the grid dimensions, which is undefined behavior. Measured results differed by architecture (arm64 saturates to 0, x86-64 yields INT64_MIN) though both happened to end in the correct -85640 warning. Now returns early and names the mask as the cause. * Bound QuickSortGrids stack depth. The double recursion reached O(n) depth when core-grid occupancies are already sorted ascending, the same class of risk that motivated making findClusterRoot iterative. It now recurses into the smaller partition and loops on the larger, capping depth at O(log n). The two partitions are disjoint so the ordering produced is unchanged and the LDF exemplars still match. * Replace the empty 'case Random: { [[fallthrough]]; }' block with adjacent case labels, which needs no attribute, and qualify SeededRandom consistently. * Use getDataRefAs instead of dereferencing the raw getDataAs pointer when resizing the cluster Attribute Matrix. * Correct a copy/paste reference to "3D data" in the 2D grid comment. Filter: * Reword the Minimum Points help text to say it is a per-grid-cell occupancy threshold rather than a count of neighbors within Epsilon. Deviation DBSCAN-D1 names the old wording as a source of user surprise. Tests: * Add analytical fixture F3 pinning the all-points-masked contract. * Read the seed back from the seed array and report it via INFO in RandomTestCase2D. ParseOrder::Random now draws a time-based seed, so the cluster-size comparison is non-deterministic and a failure would otherwise not be reproducible. Also assert SeededRandom round-trips the user seed, which was previously untested. * Replace raw getDataAs pointer dereferences on the Attribute Matrix with REQUIRE_NOTHROW plus getDataRefAs. * Correct the F2 comment describing the grid as 1x1. Documentation: * Note that GDCF can still recover sparse groups as border points of an existing cluster, so only isolated groups become noise. * Update the V&V report: record the ParseOrder::Random seed bug as found and fixed rather than "no bugs found", rewrite the stale Phase 7 section, add code path 4b and fixture F3, and drop absolute developer-machine paths. Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
PR 1702 Code Review
Memory / Lifetime Issues
CPU / Algorithm Efficiency(Deferred — both items change reproducible output for a given seed, so they need a deviation entry rather than a quiet fix. Flagging, not fixing.)
Naming Consistency
Const-Correctness
Readability
UX / Human Interface GuidelinesNo UI changes in this PR. The only user-facing string change is the Robustness / Defensive
Bugs
Documentation
Confirmed Correct (no action needed)
|
imikejackson
left a comment
There was a problem hiding this comment.
See comments on the PR
ComputeCAxisLocations (BlueQuartzSoftware#1679) merged, taking develop from 24/29 to 25/29 on the MTR closure. * Reduce the merge backlog to four closure PRs and record that three of them belong to a single engineer, making the critical path to the SBIR deliverable one person's revision queue * Note that BlueQuartzSoftware#1701 has been approved and unmerged since 2026-08-07 and grows a conflict surface against every V&V PR touching a report header * Record DBSCAN as submitted (BlueQuartzSoftware#1702) rather than in progress on a branch * Refresh counts: 34 reports on develop of 40 authored, 43 V&V PRs Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
Only BlueQuartzSoftware#1701 landed since the last refresh; it normalizes report statuses and does not move the MTR closure, which stays at 25/29. * Mark Phase 0 item 4 done: all 34 reports on develop now lead with one of DRAFT / READY FOR REVIEW / COMPLETE (31/2/1) * Record BlueQuartzSoftware#1702 (DBSCAN) and BlueQuartzSoftware#1703 (GroupMicroTextureRegions) as open and awaiting first review, neither affecting the closure * Add a third gap to the attestation section: BlueQuartzSoftware#1703 reports that the earlier GroupMicroTextureRegions cycle claimed 9 of 9 code paths while its own table showed 7, alongside a mis-stated legacy comparison and an overstated migration impact — defects a diff-focused review misses, so vv_status.py should cross-check the dashboard against the tables * Correct the all-branches versus develop gap from 11 points to 4 Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
Review changes for PR BlueQuartzSoftware#1702. Algorithm: * Guard both HyperGridBitMap constructors against all-NaN bounds. When every point is masked off the bounds stay quiet_NaN and were then cast to usize to compute the grid dimensions, which is undefined behavior. Measured results differed by architecture (arm64 saturates to 0, x86-64 yields INT64_MIN) though both happened to end in the correct -85640 warning. Now returns early and names the mask as the cause. * Bound QuickSortGrids stack depth. The double recursion reached O(n) depth when core-grid occupancies are already sorted ascending, the same class of risk that motivated making findClusterRoot iterative. It now recurses into the smaller partition and loops on the larger, capping depth at O(log n). The two partitions are disjoint so the ordering produced is unchanged and the LDF exemplars still match. * Replace the empty 'case Random: { [[fallthrough]]; }' block with adjacent case labels, which needs no attribute, and qualify SeededRandom consistently. * Use getDataRefAs instead of dereferencing the raw getDataAs pointer when resizing the cluster Attribute Matrix. * Correct a copy/paste reference to "3D data" in the 2D grid comment. Filter: * Reword the Minimum Points help text to say it is a per-grid-cell occupancy threshold rather than a count of neighbors within Epsilon. Deviation DBSCAN-D1 names the old wording as a source of user surprise. Tests: * Add analytical fixture F3 pinning the all-points-masked contract. * Read the seed back from the seed array and report it via INFO in RandomTestCase2D. ParseOrder::Random now draws a time-based seed, so the cluster-size comparison is non-deterministic and a failure would otherwise not be reproducible. Also assert SeededRandom round-trips the user seed, which was previously untested. * Replace raw getDataAs pointer dereferences on the Attribute Matrix with REQUIRE_NOTHROW plus getDataRefAs. * Correct the F2 comment describing the grid as 1x1. Documentation: * Note that GDCF can still recover sparse groups as border points of an existing cluster, so only isolated groups become noise. * Update the V&V report: record the ParseOrder::Random seed bug as found and fixed rather than "no bugs found", rewrite the stale Phase 7 section, add code path 4b and fixture F3, and drop absolute developer-machine paths. Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
- Algorithm hardening and cleanup - New tests to qualify oracle - Intial complete V&V files, cleanup pass pending
Review changes for PR BlueQuartzSoftware#1702. Algorithm: * Guard both HyperGridBitMap constructors against all-NaN bounds. When every point is masked off the bounds stay quiet_NaN and were then cast to usize to compute the grid dimensions, which is undefined behavior. Measured results differed by architecture (arm64 saturates to 0, x86-64 yields INT64_MIN) though both happened to end in the correct -85640 warning. Now returns early and names the mask as the cause. * Bound QuickSortGrids stack depth. The double recursion reached O(n) depth when core-grid occupancies are already sorted ascending, the same class of risk that motivated making findClusterRoot iterative. It now recurses into the smaller partition and loops on the larger, capping depth at O(log n). The two partitions are disjoint so the ordering produced is unchanged and the LDF exemplars still match. * Replace the empty 'case Random: { [[fallthrough]]; }' block with adjacent case labels, which needs no attribute, and qualify SeededRandom consistently. * Use getDataRefAs instead of dereferencing the raw getDataAs pointer when resizing the cluster Attribute Matrix. * Correct a copy/paste reference to "3D data" in the 2D grid comment. Filter: * Reword the Minimum Points help text to say it is a per-grid-cell occupancy threshold rather than a count of neighbors within Epsilon. Deviation DBSCAN-D1 names the old wording as a source of user surprise. Tests: * Add analytical fixture F3 pinning the all-points-masked contract. * Read the seed back from the seed array and report it via INFO in RandomTestCase2D. ParseOrder::Random now draws a time-based seed, so the cluster-size comparison is non-deterministic and a failure would otherwise not be reproducible. Also assert SeededRandom round-trips the user seed, which was previously untested. * Replace raw getDataAs pointer dereferences on the Attribute Matrix with REQUIRE_NOTHROW plus getDataRefAs. * Correct the F2 comment describing the grid as 1x1. Documentation: * Note that GDCF can still recover sparse groups as border points of an existing cluster, so only isolated groups become noise. * Update the V&V report: record the ParseOrder::Random seed bug as found and fixed rather than "no bugs found", rewrite the stale Phase 7 section, add code path 4b and fixture F3, and drop absolute developer-machine paths. Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
* findClusterRoot, infer and canMerge only read state, so declare them const. ProcessSection and QuickSortGrids in the same class were already const; these three were the outliers. Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
- added a deviation to reflect it - clean up vv docs
aac1117 to
a3997af
Compare
* - Fix bug in random seed defaulting to user seed - Algorithm hardening and cleanup - New tests to qualify oracle - Intial complete V&V files, cleanup pass pending * final changes - ready for review * REV: DBSCAN review fixes - recursion depth, NaN bounds guard, docs Review changes for PR BlueQuartzSoftware#1702. Algorithm: * Guard both HyperGridBitMap constructors against all-NaN bounds. When every point is masked off the bounds stay quiet_NaN and were then cast to usize to compute the grid dimensions, which is undefined behavior. Measured results differed by architecture (arm64 saturates to 0, x86-64 yields INT64_MIN) though both happened to end in the correct -85640 warning. Now returns early and names the mask as the cause. * Bound QuickSortGrids stack depth. The double recursion reached O(n) depth when core-grid occupancies are already sorted ascending, the same class of risk that motivated making findClusterRoot iterative. It now recurses into the smaller partition and loops on the larger, capping depth at O(log n). The two partitions are disjoint so the ordering produced is unchanged and the LDF exemplars still match. * Replace the empty 'case Random: { [[fallthrough]]; }' block with adjacent case labels, which needs no attribute, and qualify SeededRandom consistently. * Use getDataRefAs instead of dereferencing the raw getDataAs pointer when resizing the cluster Attribute Matrix. * Correct a copy/paste reference to "3D data" in the 2D grid comment. Filter: * Reword the Minimum Points help text to say it is a per-grid-cell occupancy threshold rather than a count of neighbors within Epsilon. Deviation DBSCAN-D1 names the old wording as a source of user surprise. Tests: * Add analytical fixture F3 pinning the all-points-masked contract. * Read the seed back from the seed array and report it via INFO in RandomTestCase2D. ParseOrder::Random now draws a time-based seed, so the cluster-size comparison is non-deterministic and a failure would otherwise not be reproducible. Also assert SeededRandom round-trips the user seed, which was previously untested. * Replace raw getDataAs pointer dereferences on the Attribute Matrix with REQUIRE_NOTHROW plus getDataRefAs. * Correct the F2 comment describing the grid as 1x1. Documentation: * Note that GDCF can still recover sparse groups as border points of an existing cluster, so only isolated groups become noise. * Update the V&V report: record the ParseOrder::Random seed bug as found and fixed rather than "no bugs found", rewrite the stale Phase 7 section, add code path 4b and fixture F3, and drop absolute developer-machine paths. Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net> * REV: Mark DBSCAN read-only cluster-forest helpers const * findClusterRoot, infer and canMerge only read state, so declare them const. ProcessSection and QuickSortGrids in the same class were already const; these three were the outliers. Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net> * address review feedback * - change core grid shuffling mechanic (downstream effects) - added a deviation to reflect it - clean up vv docs --------- Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net> Co-authored-by: Michael Jackson <mike.jackson@bluequartz.net>
Referenced work file: dbscan_vv is in OneDrive