Umbrella for one root cause diagnosed independently in four places. Two genuine IK branches coincide or nearly coincide, and the pipeline resolves that with a fixed constant or an arbitrary basis instead of from the problem's structure. The result is silently missing branches (never wrong ones: FK certification holds everywhere).
| Where |
Stage |
Current handling |
Symptom |
| #595 general-6R RR |
eigensolve |
reads an arbitrary basis vector of a 2-D eigenspace |
1–2 branches lost at a shared linearity-joint value, finite or at π; near-repeats lost for δ ≲ 5e-9 |
| #597, #566 (#559) spherical SP3/SP4 near a fold |
final dedup |
merges anything within subproblem_dedup = 1e-3 rad, and the survivor is chosen by 1e-16 residual noise |
8 → 4 solutions within ~5e-4 rad of a fold; seed recovery is a coin flip |
| #598 (part 2) SRS SP4 near full extension |
subproblem gate |
rejects |ratio| > 1 + 1e-9 |
a near-tangent double root, pushed past 1 by approximation drift, gives no candidates |
The principle
Multiplicity is a property of the problem at the root. Decide it from the local conditioning, and resolve it structurally:
-
Root level, detect. Use a scale-relative gap test: singular-value gap of M(x) for RR, discriminant relative to its conditioning for SP3/SP4. No absolute constants.
-
Root level, resolve.
-
Solution level: dedup merges only the same root. Merge two candidates only if they are the same solution, for example:
Never merge on a fixed 1e-3 alone. When a merge does happen, pick the representative deterministically, not by residual noise.
This belongs in the shared subproblem, eigensolve and dedup layers of both backends. The C++ side carries the same 1e-3 default (subproblems.hpp:26, rescue.hpp:62).
Public-contract decision needed first
Today subproblem_dedup = 1e-3 effectively means "solutions closer than 1 mrad are one solution". Under this principle, poses near folds return 8 distinct solutions instead of 4. Either:
- (A) adopt the "same root" semantics (more solutions near folds, and seed recovery becomes reliable), or
- (B) keep 1e-3 as a documented "physically indistinguishable" radius, choose the representative deterministically, and set seed-recovery tolerances ≥ 1e-3.
Related
Umbrella for one root cause diagnosed independently in four places. Two genuine IK branches coincide or nearly coincide, and the pipeline resolves that with a fixed constant or an arbitrary basis instead of from the problem's structure. The result is silently missing branches (never wrong ones: FK certification holds everywhere).
subproblem_dedup = 1e-3rad, and the survivor is chosen by 1e-16 residual noise|ratio| > 1 + 1e-9The principle
Multiplicity is a property of the problem at the root. Decide it from the local conditioning, and resolve it structurally:
Root level, detect. Use a scale-relative gap test: singular-value gap of M(x) for RR, discriminant relative to its conditioning for SP3/SP4. No absolute constants.
Root level, resolve.
main.Solution level: dedup merges only the same root. Merge two candidates only if they are the same solution, for example:
Never merge on a fixed 1e-3 alone. When a merge does happen, pick the representative deterministically, not by residual noise.
This belongs in the shared subproblem, eigensolve and dedup layers of both backends. The C++ side carries the same 1e-3 default (
subproblems.hpp:26,rescue.hpp:62).Public-contract decision needed first
Today
subproblem_dedup = 1e-3effectively means "solutions closer than 1 mrad are one solution". Under this principle, poses near folds return 8 distinct solutions instead of 4. Either:Related
sinfilters, which cannot see offset-elbow or shoulder folds.