perf: speed up area preservation with Newton/Steiner buffer search - #8
Merged
Merged
Conversation
Replace the bracketed Brent's-method search in _preserve_area_with_buffer with a Steiner-quadratic seed (A(d) ~= A0 + L*d + pi*d^2) refined by Newton's method, using the measured boundary length as the derivative (dA/dd equals the offset's perimeter), so no bracketing is needed. This cuts buffer operations per ring from ~5-6 to ~1-2. On examples/Water.gpkg the full single-core pipeline is ~1.3x faster at the default 5 iterations (5.1s -> 3.8s). Output is unchanged within the area tolerance (per-polygon symmetric difference <= 0.005%, area accuracy identical). Shapes where Newton stalls (pinch-offs, topology changes near the root) fall back to the original Brent's-method search, preserved verbatim as _preserve_area_brentq. Adds 7 tests covering the Newton path, the fallback, buffer-count regression, and Newton/brentq agreement. Co-Authored-By: Claude Opus 4.8 <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
Replaces the bracketed Brent's-method search in
_preserve_area_with_bufferwith a closed-form Steiner-quadratic seed refined by Newton's method.The buffered area of a polygon follows the Steiner expansion
A(d) ≈ A₀ + L·d + π·d²(L= perimeter), so the initial offset is found by solving that quadratic instead of a linear estimate. Each candidate is then refined with Newton's method using the measured boundary length as the derivative — the rate of area change of an outward offset equals its perimeter (coarea identity), so the derivative is essentially exact and free. Because buffered area is monotonic in distance, no bracketing is needed.This cuts buffer operations per ring from roughly 5–6 to 1–2.
Why
Profiling the full pipeline on
examples/Water.gpkgshowed area preservation (brentq+ repeated full-polygon buffering) was the single largest cost (~34% at 5 iterations), not the Chaikin smoothing itself.Results (single-core,
examples/Water.gpkg, old vs new)Speedup scales with iteration count and the polygon share of the workload (down to ~1.0× on hole-dominated inputs, where hole-differencing dominates). Verified equivalent across several synthetic datasets (many small, few large, with holes) as well.
Safety
_preserve_area_brentq.Tests
7 new tests in
tests/test_smoothify_core.py(Newton path on concave shapes, the fallback path, a buffer-count regression guard, Newton/brentq agreement, empty input). Full suite: 432 passed. mypy strict + ruff clean.🤖 Generated with Claude Code