You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 3f72042
Browse filesBrowse the repository at this point in the historyBrowse files
fix: broken docstring examples in Twist2/Twist3/DualQuaternion (and their shared root cause) (#225)
## Summary
Found via the sphinx-pyrunblock rollout (#221): several `.. runblock::`
docstring examples were silently baking broken tracebacks into the
published docs instead of demonstrating real output.
**Twist2.unit() / Twist3.unit()** -- branches were swapped, `self.w` had
a `S.w` typo, and the "prismatic" branch passed a wrong-shape zero
argument for `Twist2` (3-element list where a scalar is required).
**Twist2.pole** -- the docstring's own example called `S.pole()`, but
`pole` is a `@property`, not a method.
**DualQuaternion: a shared root cause across three methods** -- fixing
`SE3()`'s docstring (called `d.T` instead of the actual `d.SE3()`
method) surfaced that `UnitQuaternion.conj()` silently re-canonicalized
its result's sign, which is correct for *constructing* a UnitQuaternion
(q and -q are the same rotation) but wrong for conjugation, an algebraic
operation that must satisfy `q*conj(q) == 1`. Fixed `Quaternion.conj()`
itself rather than routing around it at each call site. This one fix
resolved three separate, previously-untested bugs:
- `SE3()`: silently returned a transform with negated translation for
any rotation with negative quaternion scalar part.
- `norm()`: crashed outright (`math domain error`) for the same reason
-- also added a small floating-point clamp for the
mathematically-non-negative-but-can-round-negative norm-squared terms.
- Vector transformation (`dq * v`): unrelated to the sign bug --
affected *every* case regardless of sign. The textbook `q*P*conj(q)`
sandwich product's translation terms cancel to exactly zero under this
class's own dual-part embedding convention (`dual = 0.5*Pure(t)*real`).
Reused the already-correct `SE3()` extraction instead of hand-deriving a
second, convention-specific sandwich formula.
## Test coverage
All of the above had zero prior test coverage -- existing DualQuaternion
tests used `SE3.Rx(pi/4)` (no translation, positive quaternion scalar
part), which can't exercise any of these bugs. Added regression tests
for `conj()`'s sign behaviour, both branches of
`Twist2`/`Twist3.unit()`, `Twist2`/`Twist3.pole`, and `DualQuaternion`'s
`SE3()`/`norm()`/vector-transform.
## Test plan
- [x] Full suite: 334 passed (up from 326), 0 regressions
- [x] Real sphinx-build verification (isolated venv, before/after this
branch): RUNBLOCK-ERROR count 6 -> 0, warning count unchanged at 14
(confirmed stable across repeat builds of both branches, ruling out
build-to-build nondeterminism as an explanation either way)
0 commit comments