Repository navigation
Description
Describe the bug
svdtf documents an SE(3) transformation that minimizes mean squared error between associated point clouds. When the unconstrained SVD rotation has determinant -1, the current implementation negates the whole rotation. This makes the determinant positive, but it need not minimize the rigid-alignment objective.
A six-point, centered example:
import torch
import pypose as pp
source = torch.tensor([
[3., 0., 0.], [-3., 0., 0.],
[0., 2., 0.], [0., -2., 0.],
[0., 0., 1.], [0., 0., -1.],
], dtype=torch.float64)
target = source * torch.tensor([1., 1., -1.])
transform = pp.svdtf(source, target)
print(transform.matrix())
print("returned SSE:", (transform.Act(source) - target).square().sum().item())
print("identity SSE:", (source - target).square().sum().item())Observed on unchanged main revision e37ed16688176596bfb60b1b9c525ba117e0688c:
tensor([[-1., 0., 0., 0.],
[ 0., -1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]], dtype=torch.float64)
returned SSE: 112.0
identity SSE: 8.0
The same result occurs with float32. Identity is a valid rigid transformation with a strictly smaller error. It is also globally optimal here: the centered cross-covariance is diag(18, 8, -2), with singular values (18, 8, 2). The determinant-constrained Procrustes bound gives minimum SSE 28 + 28 - 2*(18 + 8 - 2) = 8, attained by identity.
The current reflection branch in pypose/function/geometry.py uses R[mask] = -R[mask]. The determinant correction should change only the least-significant singular direction, rather than all three. This concerns the rigid svdtf helper, not the separate svdstf scale-alignment implementation or the earlier pixel2point camera-broadcast fix.
Following the contribution guide, I intend to contribute a minimal determinant-correction fix and regression tests covering the objective, proper rotations, translations, batching/broadcasting, and ordinary exact-rigid controls. Project code has not been modified yet. This report establishes the native CPU baseline and mathematical counterexample; it does not claim a passing full test suite or an end-to-end ICP/EPnP improvement.
Versions
Source revision: e37ed16688176596bfb60b1b9c525ba117e0688c.
The upstream environment-info helper produced the following output. Its unrelated crash-dump directory scan was not invoked.
PyTorch version: 2.7.1+cpu
Is debug build: False
CUDA used to build PyTorch: None
ROCM used to build PyTorch: N/A
OS: Debian GNU/Linux 13 (trixie) (x86_64)
GCC version: (Debian 14.2.0-19) 14.2.0
Clang version: Could not collect
CMake version: Could not collect
Libc version: glibc-2.41
Python version: 3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ] (64-bit runtime)
Python platform: Linux-6.18.55-x86_64-with-glibc2.41
Is CUDA available: False
CUDA runtime version: No CUDA
GPU models and configuration: No CUDA
Nvidia driver version: No CUDA
cuDNN version: No CUDA
HIP runtime version: N/A
MIOpen runtime version: N/A
Is XNNPACK available: True
Versions of relevant libraries:
[pip3] numpy==2.3.5
[pip3] torch==2.7.1+cpu
[conda] Could not collect
Activity
fix(geometry): preserve svdtf rigid-alignment optimum (pypose#437)