Smithsonian / Smithsonian/layup
Degrees of freedom underflow when rejection leaves fewer observations than parameters
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 10
- Forks
- 2
- Avg merge
- 1d 43m
- Merged PRs (30d)
- 58
Description
A fit left with fewer observations than parameters is reported as converged and accepted, because the reduced chi-square check that should catch it is disabled by an unsigned-integer underflow.
orbit_fit computes the degrees of freedom in two places, both as size_t:
orbit_fit.cpp:1311 size_t ndof = (prior_info != nullptr) ? nrows : (nrows - npar);
orbit_fit.cpp:1527 dof = total_residual_rows(detections) - npar; // size_t, declared :1466
Two surviving astrometric observations give nrows = 4 and npar = 6, so both expressions wrap to 18446744073709551614. The gate immediately below the first one,
if (ndof > 0 && (chi2_final / ndof) > thresh) // thresh = 10.0
then cannot fire: the wrapped value passes ndof > 0, and the chi-square is divided by 1.8e19. flag = 2 is unreachable exactly where the fit is under-determined. The second expression wraps and narrows back to the int field result.ndof, which is emitted as -2, so any consumer forming csq / ndof gets a negative reduced chi-square.
This is reachable through the outlier-rejection loop, which sits outside Layup and can drive an object below three observations. In the full-catalog re-fit, K19SM7P has four observations with two rejected and is reported ok with ndof = -2; a downstream scorer read its csq / ndof of -134.8 as a chi-square improvement.
The defect can only make flag = 2 too rare, never too common, so counts of chi-square-rejected fits are a lower bound rather than a figure at risk.
Suggested fix: compute both in a signed type, and treat dof <= 0 as an explicit refusal to certify rather than a skipped check. bk_fit.cpp:209 has the same size_t expression but is unreachable, guarded by the detections.size() < 3 early return at bk_fit.cpp:43; worth making signed at the same time.
Drafted with Claude Opus 5.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing orbit_fit.cpp around lines 1311, 1466, and 1527, then reproduce the K19SM7P full-catalog re-fit with two rejected observations. Check bk_fit.cpp lines 43 and 209 for the related expression. Done means under-determined fits are not certified, flag = 2 can be reached, and result.ndof remains valid for downstream reduced-chi-square calculations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- data
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100