Skip to content

Commit 3e6903a

Browse files
authored
chore(release): v1.4.1 (#101)
* chore(release): v1.4.1 Patch bump for the per-patch heap-traffic refactor (#100). pypatchworkpp.patchworkpp gains 14.8% Hz (97.5 -> 111.9 Hz on KITTI seq 00, i7-12700), driven by killing short-lived vector<PointXYZ> / Eigen::Matrix allocations in R-VPF + R-GPF. Closes part of #96. Numerical equivalence verified end-to-end on KITTI seq 00 (4541 frames): F1 delta 0.00 for patchwork classic (bit-identical), +0.01 for patchwork++ (within the ±0.05 macro budget). Bumps: - python/pyproject.toml 1.4.0 -> 1.4.1 - cpp/CMakeLists.txt 1.4.0 -> 1.4.1 CHANGELOG.md updated with the full v1.4.1 entry. See #100. * chore(release): mdformat CHANGELOG.md * chore(release): mdformat 0.7.9 escapes
1 parent 1f623d5 commit 3e6903a

3 files changed

Lines changed: 81 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,70 @@
11
# Changelog
22

3+
## v1.4.1
4+
5+
### Perf — `pypatchworkpp.patchworkpp` per-patch heap traffic eliminated
6+
7+
Three changes inside `PatchWorkpp::extract_piecewiseground` and
8+
`PatchWorkpp::estimate_plane` take KITTI seq 00 from 10.26 ms to
9+
8.94 ms per frame (**97.5 Hz → 111.9 Hz, +14.8% Hz**, median of 3
10+
runs, i7-12700). This closes the part of #96 that was driven by
11+
short-lived allocations in R-VPF + R-GPF.
12+
13+
**High-impact (this is where the +14.8% comes from):**
14+
15+
- `estimate_plane`: drop the `Eigen::MatrixX3f eigen_ground`,
16+
`centered`, and `centered.adjoint() * centered` heap allocations.
17+
Replace with a single-pass scalar accumulation of mean and 9
18+
cross-products, then build the 3x3 covariance on the stack.
19+
- `extract_piecewiseground`: promote `src_wo_verticals` and
20+
`src_tmp` to reused instance scratch members. `vector::clear()`
21+
keeps capacity, so per-patch malloc pressure on the glibc heap
22+
(which was serialising the loop, see #96) drops away after the
23+
first few patches.
24+
- `estimateGround` main loop: `auto& zone` instead of `auto zone`
25+
for `ConcentricZoneModel_[zone_idx]`. Avoids a deep-copy of the
26+
full 3-level nested vector per outer iteration. Safe because each
27+
`(zone, ring, sector)` patch is read once and the CZM is flushed
28+
at the top of every `estimateGround` call.
29+
30+
**Lower-impact, kept for cleanliness:**
31+
32+
- `JacobiSVD<Matrix3f>` to `SelfAdjointEigenSolver::computeDirect`
33+
for the 3x3 PSD covariance in both `cpp/common/src/plane_fit.cpp`
34+
and the in-place `PatchWorkpp::estimate_plane`. Closed-form, no
35+
Jacobi iterations. `singular_values_` is repacked descending so
36+
every consumer (`linearity_` / `planarity_` in `common`,
37+
`flatness_thr` index `(2)` in patchwork classic,
38+
`ground_flatness=minCoeff()` and `line_variable=sv(0)/sv(1)` in
39+
patchwork++) keeps the same convention bit-for-bit.
40+
- `const&` on `addCloud`'s `add` parameter, `RevertCandidate` loop
41+
vars, and the `temporal_ground_revert` /
42+
`calc_point_to_plane_d` / `calc_mean_stdev` signatures.
43+
44+
Patchwork classic is unaffected on the perf side: TBB
45+
`parallel_for` already amortises allocations across cores and SVD
46+
is sub-us/patch.
47+
48+
### Numerical equivalence
49+
50+
KITTI seq 00 (4541 frames), v1.4.0 to v1.4.1:
51+
52+
| Method (protocol) | Before | After | Δ F1 |
53+
| ------------------ | -------------------------- | -------------------------- | ----: |
54+
| `patchwork` (pw) | P 92.34, R 94.64, F1 93.41 | P 92.34, R 94.64, F1 93.41 | 0.00 |
55+
| `patchworkpp` (pp) | P 94.88, R 98.47, F1 96.62 | P 94.89, R 98.48, F1 96.63 | +0.01 |
56+
57+
Algebraic identity of `JacobiSVD` vs `eigh` verified on 500 real
58+
KITTI patch covariances: `normal_` (up to sign),
59+
`singular_values_`, `linearity_`, `planarity_`, `ground_flatness`,
60+
`line_variable` all match to FP precision. Both within the ±0.05
61+
macro budget.
62+
63+
### References
64+
65+
- #100 — PR (perf: alloc-free + eigh)
66+
- #96 — Issue (R-VPF / R-GPF allocation profile)
67+
368
## v1.4.0
469

570
### Refactor — shared `common` library + optional TBB parallelisation
@@ -29,10 +94,10 @@ order so numerical results are byte-identical to the sequential path.
2994

3095
Measured on KITTI seq 00 (i7-12700, 24 logical cores):
3196

32-
| Configuration | Median ms/frame | Median Hz |
33-
| -- | --: | --: |
34-
| `--method patchwork` single-thread (taskset -c 0) | 8.31 | 120.4 |
35-
| `--method patchwork` parallel (TBB default scheduler) | **4.81** | **207.8** |
97+
| Configuration | Median ms/frame | Median Hz |
98+
| ----------------------------------------------------- | --------------: | --------: |
99+
| `--method patchwork` single-thread (taskset -c 0) | 8.31 | 120.4 |
100+
| `--method patchwork` parallel (TBB default scheduler) | **4.81** | **207.8** |
36101

37102
**1.73× speedup**. TBB is an **optional** build dependency: missing
38103
TBB causes a CMake STATUS message and falls back to a sequential
@@ -63,10 +128,10 @@ or a real user CPU complaint).
63128
KITTI 00-10 full sweep (23,201 frames), Patchwork++ paper protocol,
64129
v1.3.1 → v1.4.0:
65130

66-
| Method | F1 v1.3.1 | F1 v1.4.0 | Δ |
67-
| --- | --- | --- | --- |
68-
| `--method patchwork` | 96.0172 | 96.0172 | 0 (byte-identical) |
69-
| `--method patchworkpp` | 96.2918 | 96.2919 | +0.0001 (float noise) |
131+
| Method | F1 v1.3.1 | F1 v1.4.0 | Δ |
132+
| ---------------------- | --------- | --------- | --------------------- |
133+
| `--method patchwork` | 96.0172 | 96.0172 | 0 (byte-identical) |
134+
| `--method patchworkpp` | 96.2918 | 96.2919 | +0.0001 (float noise) |
70135

71136
Both well within the ±0.05 budget set in the refactor plan.
72137

@@ -111,12 +176,12 @@ parameters (`uprightness_thr=0.707`, `using_global_thr=false`) on SemanticKITTI
111176
sequences 00–10 (23,201 frames), under the Patchwork++ paper evaluation
112177
protocol (Sec. IV.A — VEGETATION excluded):
113178

114-
| Configuration | Precision | Recall | F1 |
115-
| --- | --- | --- | --- |
116-
| v1.2.0 (`pypatchworkpp.patchwork`) | 89.70 | 98.49 | 93.73 |
117-
| **v1.3.0 (`pypatchworkpp.patchwork`)** | **94.64** | **97.58** | **96.02** |
118-
| Original Patchwork ROS 2 (reference) | 94.38 | 97.90 | 96.05 |
119-
| Patchwork++ paper Table I, Patchwork \[1\] | 94.23 | 97.62 | 95.88 |
179+
| Configuration | Precision | Recall | F1 |
180+
| ---------------------------------------- | --------- | --------- | --------- |
181+
| v1.2.0 (`pypatchworkpp.patchwork`) | 89.70 | 98.49 | 93.73 |
182+
| **v1.3.0 (`pypatchworkpp.patchwork`)** | **94.64** | **97.58** | **96.02** |
183+
| Original Patchwork ROS 2 (reference) | 94.38 | 97.90 | 96.05 |
184+
| Patchwork++ paper Table I, Patchwork \[1\] | 94.23 | 97.62 | 95.88 |
120185

121186
**+2.29 F1** vs v1.2.0; within ±0.14 F1 of the original Patchwork ROS 2 build
122187
and within paper run-to-run variance of Table I.

cpp/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.11)
2-
project(patchworkpp VERSION 1.4.0)
2+
project(patchworkpp VERSION 1.4.1)
33

44
option(USE_SYSTEM_EIGEN3 "Use system pre-installed Eigen" OFF)
55
option(INCLUDE_CPP_EXAMPLES "Include C++ example codes, which require Open3D for visualization" OFF)

python/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
44

55
[project]
66
name = "pypatchworkpp"
7-
version = "1.4.0"
7+
version = "1.4.1"
88
requires-python = ">=3.8"
99
description = "ground segmentation"
1010
dependencies = [

0 commit comments

Comments
 (0)