|
1 | 1 | # Changelog |
2 | 2 |
|
| 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 | + |
3 | 68 | ## v1.4.0 |
4 | 69 |
|
5 | 70 | ### Refactor — shared `common` library + optional TBB parallelisation |
@@ -29,10 +94,10 @@ order so numerical results are byte-identical to the sequential path. |
29 | 94 |
|
30 | 95 | Measured on KITTI seq 00 (i7-12700, 24 logical cores): |
31 | 96 |
|
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** | |
36 | 101 |
|
37 | 102 | **1.73× speedup**. TBB is an **optional** build dependency: missing |
38 | 103 | TBB causes a CMake STATUS message and falls back to a sequential |
@@ -63,10 +128,10 @@ or a real user CPU complaint). |
63 | 128 | KITTI 00-10 full sweep (23,201 frames), Patchwork++ paper protocol, |
64 | 129 | v1.3.1 → v1.4.0: |
65 | 130 |
|
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) | |
70 | 135 |
|
71 | 136 | Both well within the ±0.05 budget set in the refactor plan. |
72 | 137 |
|
@@ -111,12 +176,12 @@ parameters (`uprightness_thr=0.707`, `using_global_thr=false`) on SemanticKITTI |
111 | 176 | sequences 00–10 (23,201 frames), under the Patchwork++ paper evaluation |
112 | 177 | protocol (Sec. IV.A — VEGETATION excluded): |
113 | 178 |
|
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 | |
120 | 185 |
|
121 | 186 | **+2.29 F1** vs v1.2.0; within ±0.14 F1 of the original Patchwork ROS 2 build |
122 | 187 | and within paper run-to-run variance of Table I. |
|
0 commit comments