Smithsonian / Smithsonian/layup

Degrees of freedom underflow when rejection leaves fewer observations than parameters

Open
#581 0 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.