From b4603013c77eb50c7888dc4c255417dab004e0cd Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Wed, 15 Jul 2026 17:31:35 +0200 Subject: [PATCH 1/4] Stabilize SO(3) chordal weight normalization --- src/pyrecest/smoothers/so3_chordal_mean_smoother.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pyrecest/smoothers/so3_chordal_mean_smoother.py b/src/pyrecest/smoothers/so3_chordal_mean_smoother.py index 6f7798640..037bd33ff 100644 --- a/src/pyrecest/smoothers/so3_chordal_mean_smoother.py +++ b/src/pyrecest/smoothers/so3_chordal_mean_smoother.py @@ -106,13 +106,18 @@ def _normalize_weight_vector( if weights_array[idx] < 0.0: raise ValueError(f"{name} must be nonnegative.") - weight_sum = backend.sum(weights_array) - if weight_sum <= 0.0: + weight_scale = backend.max(weights_array) + if not bool(weight_scale > 0.0): + raise ValueError(f"{name} must contain at least one positive entry.") + + scaled_weights = weights_array / weight_scale + scaled_weight_sum = backend.sum(scaled_weights) + if not bool(isfinite(scaled_weight_sum)) or not bool(scaled_weight_sum > 0.0): raise ValueError(f"{name} must contain at least one positive entry.") if normalize: - return weights_array / weight_sum - return weights_array + return scaled_weights / scaled_weight_sum + return scaled_weights @staticmethod def project_to_so3(matrix): From 7e99d97f2fd32083305f7f3ea8808dc54ba20828 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Wed, 15 Jul 2026 17:32:24 +0200 Subject: [PATCH 2/4] Add SO(3) extreme-weight regression --- .../test_so3_chordal_mean_extreme_weights.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/smoothers/test_so3_chordal_mean_extreme_weights.py diff --git a/tests/smoothers/test_so3_chordal_mean_extreme_weights.py b/tests/smoothers/test_so3_chordal_mean_extreme_weights.py new file mode 100644 index 000000000..8ecf0bee9 --- /dev/null +++ b/tests/smoothers/test_so3_chordal_mean_extreme_weights.py @@ -0,0 +1,42 @@ +import numpy as np +import numpy.testing as npt + +# pylint: disable=no-name-in-module,no-member +from pyrecest.backend import array, cos, eye, sin, stack, to_numpy +from pyrecest.smoothers import SO3ChordalMeanSmoother + + +def _z_rotation(angle): + return array( + [ + [cos(angle), -sin(angle), 0.0], + [sin(angle), cos(angle), 0.0], + [0.0, 0.0, 1.0], + ] + ) + + +def test_chordal_mean_normalizes_extreme_finite_weights_stably(): + backend_dtype = to_numpy(array([1.0])).dtype + maximum = np.finfo(backend_dtype).max + rotations = stack([eye(3), _z_rotation(0.5 * np.pi)], axis=0) + + reference = SO3ChordalMeanSmoother.chordal_mean( + rotations, + weights=array([3.0, 1.0]), + ) + extreme_weights = array( + np.asarray([maximum, maximum / 3.0], dtype=backend_dtype) + ) + + result = SO3ChordalMeanSmoother.chordal_mean( + rotations, + weights=extreme_weights, + ) + + npt.assert_allclose( + to_numpy(result), + to_numpy(reference), + rtol=1.0e-5, + atol=1.0e-6, + ) From a0eac438a865eeb82655ac5de4aafb0bbb32e088 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:19:30 +0200 Subject: [PATCH 3/4] Trigger CI against repaired main --- .github/ci-refresh/4448.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ci-refresh/4448.txt diff --git a/.github/ci-refresh/4448.txt b/.github/ci-refresh/4448.txt new file mode 100644 index 000000000..41e74407b --- /dev/null +++ b/.github/ci-refresh/4448.txt @@ -0,0 +1 @@ +Temporary CI refresh marker. From 9b3917f11e4df32838b66d5cee65a25996b07e30 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:19:38 +0200 Subject: [PATCH 4/4] Remove temporary CI refresh marker --- .github/ci-refresh/4448.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/ci-refresh/4448.txt diff --git a/.github/ci-refresh/4448.txt b/.github/ci-refresh/4448.txt deleted file mode 100644 index 41e74407b..000000000 --- a/.github/ci-refresh/4448.txt +++ /dev/null @@ -1 +0,0 @@ -Temporary CI refresh marker.