Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 79 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,70 @@
# Changelog

## v1.4.1

### Perf — `pypatchworkpp.patchworkpp` per-patch heap traffic eliminated

Three changes inside `PatchWorkpp::extract_piecewiseground` and
`PatchWorkpp::estimate_plane` take KITTI seq 00 from 10.26 ms to
8.94 ms per frame (**97.5 Hz → 111.9 Hz, +14.8% Hz**, median of 3
runs, i7-12700). This closes the part of #96 that was driven by
short-lived allocations in R-VPF + R-GPF.

**High-impact (this is where the +14.8% comes from):**

- `estimate_plane`: drop the `Eigen::MatrixX3f eigen_ground`,
`centered`, and `centered.adjoint() * centered` heap allocations.
Replace with a single-pass scalar accumulation of mean and 9
cross-products, then build the 3x3 covariance on the stack.
- `extract_piecewiseground`: promote `src_wo_verticals` and
`src_tmp` to reused instance scratch members. `vector::clear()`
keeps capacity, so per-patch malloc pressure on the glibc heap
(which was serialising the loop, see #96) drops away after the
first few patches.
- `estimateGround` main loop: `auto& zone` instead of `auto zone`
for `ConcentricZoneModel_[zone_idx]`. Avoids a deep-copy of the
full 3-level nested vector per outer iteration. Safe because each
`(zone, ring, sector)` patch is read once and the CZM is flushed
at the top of every `estimateGround` call.

**Lower-impact, kept for cleanliness:**

- `JacobiSVD<Matrix3f>` to `SelfAdjointEigenSolver::computeDirect`
for the 3x3 PSD covariance in both `cpp/common/src/plane_fit.cpp`
and the in-place `PatchWorkpp::estimate_plane`. Closed-form, no
Jacobi iterations. `singular_values_` is repacked descending so
every consumer (`linearity_` / `planarity_` in `common`,
`flatness_thr` index `(2)` in patchwork classic,
`ground_flatness=minCoeff()` and `line_variable=sv(0)/sv(1)` in
patchwork++) keeps the same convention bit-for-bit.
- `const&` on `addCloud`'s `add` parameter, `RevertCandidate` loop
vars, and the `temporal_ground_revert` /
`calc_point_to_plane_d` / `calc_mean_stdev` signatures.

Patchwork classic is unaffected on the perf side: TBB
`parallel_for` already amortises allocations across cores and SVD
is sub-us/patch.

### Numerical equivalence

KITTI seq 00 (4541 frames), v1.4.0 to v1.4.1:

| Method (protocol) | Before | After | Δ F1 |
| ------------------ | -------------------------- | -------------------------- | ----: |
| `patchwork` (pw) | P 92.34, R 94.64, F1 93.41 | P 92.34, R 94.64, F1 93.41 | 0.00 |
| `patchworkpp` (pp) | P 94.88, R 98.47, F1 96.62 | P 94.89, R 98.48, F1 96.63 | +0.01 |

Algebraic identity of `JacobiSVD` vs `eigh` verified on 500 real
KITTI patch covariances: `normal_` (up to sign),
`singular_values_`, `linearity_`, `planarity_`, `ground_flatness`,
`line_variable` all match to FP precision. Both within the ±0.05
macro budget.

### References

- #100 — PR (perf: alloc-free + eigh)
- #96 — Issue (R-VPF / R-GPF allocation profile)

## v1.4.0

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

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

| Configuration | Median ms/frame | Median Hz |
| -- | --: | --: |
| `--method patchwork` single-thread (taskset -c 0) | 8.31 | 120.4 |
| `--method patchwork` parallel (TBB default scheduler) | **4.81** | **207.8** |
| Configuration | Median ms/frame | Median Hz |
| ----------------------------------------------------- | --------------: | --------: |
| `--method patchwork` single-thread (taskset -c 0) | 8.31 | 120.4 |
| `--method patchwork` parallel (TBB default scheduler) | **4.81** | **207.8** |

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

| Method | F1 v1.3.1 | F1 v1.4.0 | Δ |
| --- | --- | --- | --- |
| `--method patchwork` | 96.0172 | 96.0172 | 0 (byte-identical) |
| `--method patchworkpp` | 96.2918 | 96.2919 | +0.0001 (float noise) |
| Method | F1 v1.3.1 | F1 v1.4.0 | Δ |
| ---------------------- | --------- | --------- | --------------------- |
| `--method patchwork` | 96.0172 | 96.0172 | 0 (byte-identical) |
| `--method patchworkpp` | 96.2918 | 96.2919 | +0.0001 (float noise) |

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

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

| Configuration | Precision | Recall | F1 |
| --- | --- | --- | --- |
| v1.2.0 (`pypatchworkpp.patchwork`) | 89.70 | 98.49 | 93.73 |
| **v1.3.0 (`pypatchworkpp.patchwork`)** | **94.64** | **97.58** | **96.02** |
| Original Patchwork ROS 2 (reference) | 94.38 | 97.90 | 96.05 |
| Patchwork++ paper Table I, Patchwork \[1\] | 94.23 | 97.62 | 95.88 |
| Configuration | Precision | Recall | F1 |
| ---------------------------------------- | --------- | --------- | --------- |
| v1.2.0 (`pypatchworkpp.patchwork`) | 89.70 | 98.49 | 93.73 |
| **v1.3.0 (`pypatchworkpp.patchwork`)** | **94.64** | **97.58** | **96.02** |
| Original Patchwork ROS 2 (reference) | 94.38 | 97.90 | 96.05 |
| Patchwork++ paper Table I, Patchwork \[1\] | 94.23 | 97.62 | 95.88 |

**+2.29 F1** vs v1.2.0; within ±0.14 F1 of the original Patchwork ROS 2 build
and within paper run-to-run variance of Table I.
Expand Down
2 changes: 1 addition & 1 deletion cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.11)
project(patchworkpp VERSION 1.4.0)
project(patchworkpp VERSION 1.4.1)

option(USE_SYSTEM_EIGEN3 "Use system pre-installed Eigen" OFF)
option(INCLUDE_CPP_EXAMPLES "Include C++ example codes, which require Open3D for visualization" OFF)
Expand Down
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "pypatchworkpp"
version = "1.4.0"
version = "1.4.1"
requires-python = ">=3.8"
description = "ground segmentation"
dependencies = [
Expand Down
Loading