Increment 16b-0: the noder's verifier by sort and sweep (+ the 16b design) - #107
Merged
Merged
Conversation
… 1: measurements and prior art Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le measurement Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ests, test data, acceptance, questions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, order claim stated as measured Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The design record, docs/increments/16b-terrain-polygons.md, and the ROADMAP 16b row pointing at it. Measured on Ola's CORINE GeoPackage over three DTM10 tiles: CORINE is an exact partition after reprojection, the noder merges its doubled edges correctly, and the noder's verification is quadratic (25 s of a 30 s run on a 48 km square), so 16b-0 indexes it. Q1-Q6 open for Ola. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ead it) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
R8 step 0 was run first. Scratch _core builds, one unchanged and one with check_guarantee_14 returning at its first line, were timed through clc_nodetime.py on CORINE squares in 6603_4, on battery. At 48 km (51 791 segments) node takes 24.83 s with the verifier on and 0.047 s with it off. From 12 km to 48 km the segments grow 13.8x; the time grows 185x with the verifier on and 15x with it off. So the verifier is the quadratic, as the design supposed. The table is in 16b-terrain-polygons.md, R8. prop_noding_verifier_sweep is the invariant-critical suite. It has three layers: - sweep_box_pairs, the pinned kernel-free search, reports exactly the pairs of closed boxes the brute force finds, each once, with no cell-cell pair. Inputs: random boxes on a small lattice (ties, zero width, corner contact, long boxes) in unit, 0.1, +2^51 and -2^49 frames, and named cases (x touching, same-x verticals, corners, one ulp apart, many boxes at one x, a long box spanning all, cell before edge and edge before cell). Also early stop and determinism. - build() returns the brute-force status (I6) on random hand-built candidates (three layouts, six spacing/origin settings including next to kMaxGridIndex), on real noder output with one edge or one node added, and on named cases: duplicates in both orientations, collinear partial overlaps (vertical, horizontal, diagonal), stacked verticals, T-junctions, a cell corner graze, a corner-only box contact, long spanning edges, and huge coordinates. Each random family must give at least 15 or 20 of each status. - node<K> is unchanged: digests over integers of six fixtures, recorded from 6b4fcb9, and every Ok output on random polylines passes the brute force. The oracle is tests/cpp/support/verifier_oracle.hpp, frozen from check_guarantee_14 at 6b4fcb9. The interface is pinned under "Pinned by the red suite (16b-0)". Mutation round against an uncommitted scratch sweep. It passes this suite, test_noding_noded_pslg_builder, prop_noding_no_crossings and test_noding_node. 11 mutants killed: eviction by > (edges; cells), open y-interval, no y-test, arriving edge not tested against active cells, arriving cell not tested against active edges, eviction after the test (one late), sort by xmax, sort by (kind, index), sort by ymin, and a false from a callback not stopping the sweep. Three survive, and all three are equivalent on admissible input: - cells before edges on an x tie: both directions are tested either way. - an unpadded cell box: it is segment_meets_cell's own box test. - the cell box taken from the node point: on grid, a segment meeting a closed cell has a box containing the node; a search of 4e5 spacings and indices up to kMaxGridIndex found no cell bound reaching a neighbour node's coordinate. The eviction, late-eviction and xmax-sort mutants are killed only by the sweep layer, because on-grid violating pairs never meet at a single x. The suite is registered only once noded_pslg_builder.hpp names sweep_box_pairs (the 21a/21b guard), and the header is a configure dependency. The guard fired in both scratch trees, whose header names it. The main build exits 0 and ctest passes 781/781. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_node_releases_the_gil refuses to pass on a window under 0.05 s. The ladder_pslg fixture (48 rungs a side) cleared that floor only because the verifier's pair search was quadratic; with the sort-and-sweep verifier it nodes in ~0.003 s and the probe's precondition fails. The fixture is now 300 rungs a side (90 000 crossings): ~0.26 s here with the sweep, a 5x margin over the floor for slower CI runners. The test's bound, tick threshold and intent are unchanged. Measured on this Mac, _core.node on the ladder with the sweep: 48 rungs 0.003 s, 96 0.014 s, 150 0.042 s, 200 0.088 s, 300 0.26 s. Against the old quadratic verifier (red commit 62740a8, built in a separate worktree) the test still passes but takes ~210 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sweep_box_pairs (terrain::noding, kernel-free) reports each intersecting closed-box edge/edge and edge/cell pair exactly once; check_guarantee_14 uses it, with cell boxes padded by one spacing (R8) and clamped to +-DBL_MAX. The verifier stays always on (Ola's Q1). Written by @developer; committed by the main session after @tester's GIL-fixture amendment (cb09085). 48 km CORINE square (battery): node 24.83 s -> 0.067 s. ctest 802/802 (Release, ASan/UBSan, -ffp-contract=off); pytest 2044 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onstraint noted; 16b-0 LOC as built Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two @Reviewer findings on the 16b-0 green, as one test-only commit because both touch only test registration and a test suite, and neither changes production code. B1: tests/cpp/CMakeLists.txt no longer guards prop_noding_verifier_sweep on noded_pslg_builder.hpp naming sweep_box_pairs (the configure dependency, file(READ)/string(FIND)/if are gone); the suite is registered unconditionally, as the 21a/21b scaffold removals did. The 16b increment file's "Pinned by the red suite (16b-0)" bullet now says the guard was dropped after green. S1: the +-DBL_MAX clamp on the padded node cells in check_guarantee_14 had no test. test_noding_noded_pslg_builder gains "a huge spacing whose padded cell overflows is accepted, not thrown on": SnapGrid{1e308}, nodes (0,0) and (1,0), one open chain; build() must return Ok without throwing. Under a no-clamp mutant of the header it fails with std::invalid_argument "terrain::Box2: corners must be finite". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ier-sweep # Conflicts: # ROADMAP.md
…ical; node on 48 km CORINE layout B 84.1 s -> 0.14 s; first CORINE baseline Three bench.py pairs vs master dc372a5, back to back on battery; CORINE node timings (layouts A/B, 12-144 km), the ladder and comb worst cases, and the 48 km CORINE mesh baseline at 1 m and 10 m with the quality start on and off. Evidence in docs/benchmarks/2026-09-28/16b0-acceptance/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two rng() draws passed as function arguments are unsequenced: clang evaluates them left to right, GCC right to left, so Linux built a different fixture 5 in prop_noding_verifier_sweep and missed the recorded macOS digest. The draws now go into locals in clang's order, so kRecorded stays valid. The same pattern in prop_pslg_invariants' generated_specs (holes(rng), lines(rng)) is sequenced the same way. Braced-init draws elsewhere are already sequenced left to right. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng 4 revised)
Ola revised increment 13's ruling 4 on 2026-09-28: with no constraint
edges the VTK writer omits the LINES block. vtk 9.7.1 (CI's) rejects
`LINES 0 0` ("Error reading lines", 0 cells); a file with no LINES block
loads 4 cells and its cell data in 9.7.0 and 9.7.1 alike (re-probed on
both by stripping the block from today's writer output).
- test_io_vtk_legacy.py TestZeroEdges: no LINES section, no LINES
keyword in the ASCII bytes, and a nonempty mesh still writes LINES
before POLYGONS.
- test_io_vtk_readback.py TestEmptyCases: docstring only; its readback
assertions already state the target.
- 13-bundled-mesh.md ruling 4: a dated revision note; the original text
is kept.
Red under the current writer: the 3 new TestZeroEdges unit tests, and
under vtk 9.7.1 the 6 zero-edge readback cases (0 cells, expected 4).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruling 4 as revised by Ola on 2026-09-28: with no constraint edges the legacy VTK writer leaves the LINES block out, since vtk 9.7.1 rejects `LINES 0 0`. The module docstring's rulings 4 and 5 paragraph states the revision. Nonempty meshes are byte-identical to the previous writer (ASCII and binary, probed against 6cb72e6's module). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g unsequenced draws sequenced - 13-bundled-mesh.md: the Tests line "Zero edges: `LINES 0 0`" gets a dated revision (ruling 4: no `LINES` block), and the Empty-cases finding is qualified as vtk 9.7.0's (9.7.1 rejects `LINES 0 0`). History kept. - 56d50e8 fixed the only two digest-relevant sites, not every one. These are the rest. Draws in call arguments or in the operands of one expression are unsequenced (clang left first, GCC right first), so GCC and clang tested different samples and a failing seed did not reproduce across compilers. All of them now go through locals in clang's left-to-right order, so today's macOS samples are unchanged: - test_mesh_row_spans.cpp: Rng::coord's `node() + unit()`, and every generator (node_only, mixed, sliver, collinear_but_one's two coins, near_node's two nudges, horizontal, vertical, on_border) via new Rng::node_vertex / coord_vertex helpers and locals. - prop_refinement_scan_equivalence.cpp: Rng::coord's operand pair and the mv(draw, draw) sites in meshes(), through the same helpers. - test_predicates_detria_exact.cpp: as_ccw(blow_up(..) x3) on the near-cocircular cluster; blow_up draws twice per call. A scan over tests/cpp for calls with draws in two or more arguments flags all of these on the pre-fix files and nothing after. The two engine-wrapping structs were read by eye for operand pairs. test_mesh_row_spans, prop_refinement_scan_equivalence and test_predicates_detria_exact pass on macOS (clang). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
docs/increments/16b-terrain-polygons.md): terrain polygons with CORINE over Norway, with Ola's rulings Q1-Q6 (2026-09-28).check_guarantee_14) found intersecting pairs by brute force, which was 99.8 % ofnodeon real CORINE.terrain::noding::sweep_box_pairsreports each intersecting closed-box edge/edge and edge/cell pair exactly once, by sort and sweep; the verifier uses it, stays always on (Ola's Q1), pads cells by one spacing and clamps to ±DBL_MAX. 98 production lines (C++ header only). Noded output unchanged.62740a8(step 0 confirmed the premise first), test amendmentcb09085(the GIL probe's ladder enlarged), greenaa35a38,75f3845(red-step guard dropped; huge-spacing clamp pinned). Invariant-criticalprop_noding_verifier_sweepagainst a brute-force oracle; mutation round 11/14 killed, 3 equivalent.Acceptance (@Perf, battery;
docs/benchmarks/2026-09-28/16b0-acceptance*)1 m benchmark and thread sweep: no change (pooled median −0.28 %), meshes identical. First CORINE baseline recorded (at 10 m the quality start makes the mesh 2.27x its size without; input for 20c).
Review
@Reviewer: CHANGES REQUESTED twice (bookkeeping, citations, a test gap), approved on the final docs-only fix. Local: ctest 803/803 (Release, ASan/UBSan, -ffp-contract=off), pytest 2103 passed.
🤖 Generated with Claude Code