VBPCApy 0.5.0 qualification¶
Version 0.5 introduces native scikit-learn estimators and selection helpers with
samples × features inputs. Existing 0.4 applications need an explicit migration:
there is no shape guessing. The feature-first adapter remains available from
vbpca_py.legacy; the low-level pca_full layout is unchanged.
The migration guide and
compatibility-mode comparison provide executed
examples and describe the observation-policy changes.
Published artifacts are available from the GitHub release, PyPI and the version-specific Zenodo record. The Zenodo concept DOI resolves to the newest archived version.
Public compatibility changes¶
| Contract | Native 0.5 behavior | Migration |
|---|---|---|
| Input layout | Samples × features for estimators, selection and raw-cell CV | Transpose old feature-first inputs or use the explicit legacy API |
| Fitted factors | Components (q,p), joint training scores (n,q), mean (p,) |
Update consumers of fitted arrays |
| Projection | fit_transform(X) returns fit(X).transform(X) conditional means |
Access joint variational training means through scores_ |
| Observation mode | Native estimators and selection default to modern |
Specify a mode explicitly for reproductions; the legacy adapter keeps its historical default |
| Solver options | Explicit constructor parameters, string-compatible enums and frozen PCAOptions |
Use set_params, not mutation of .opts; unknown options fail |
| Stored artifacts | Native estimators and prepared raw-CV folds have versioned layouts | Rebuild pre-0.5 native pickles and old prepared folds; do not reinterpret their axes |
Rank zero remains a supported mean-only model. Projection can return the full
latent covariance through transform_posterior; ordinary transform avoids
that covariance bank. New-row Gaussian scoring integrates latent scores under
fitted loading means and noise. It does not integrate loading uncertainty and
is distinct from cellwise PRMS/Brier selection.
Native rank-zero score/loading updates return validated empty outputs directly. This avoids the empty matrix solve that crashes with Eigen 3.3.4 in manylinux builds. A dedicated older-header CI job supplements the current-header checks.
Modern observations retain finite numeric zeros and small values. Sparse stored
entries are observed and absent entries are missing; sparse conversions and
probe splitting preserve stored zeros. Explicit masks are consumed before
learned preprocessing and categorical expansion. The public make_xprobe_mask
helper also defaults to modern splitting; historical helper-based reproduction
requires compat_mode="strict_legacy". Observed raw sparse infinities are checked
before duplicate aggregation. Fits refuse observed probes that would be lost
when training-only empty axes are removed.
Pipeline, types and examples¶
Preprocessors use native estimator validation, transactional fitted state and
fitted feature names. Strict numeric encoding schemas require usable affine
metadata for continuous/ordinal decoding. ObservationMasker routes the original
mask before expansion, including through row CV and GridSearchCV. Optional pandas
and Polars outputs preserve the documented names and row order. The complete
Pipeline example projects independent rows and decodes in original input units.
Public configuration/result annotations, numerical array dtypes, slotted records
and ownership contracts ship with py.typed. Strict consumer typing remains a
separate gate from numerical validation. Six executed gallery sources, the
mixed-data notebook and maintained documentation blocks exercise the installed
API; short example fits do not establish convergence or predictive calibration.
Qualified runtime changes¶
Marginal variance uses bounded covariance matrix products. Sparse updates reuse CSR/CSC views and avoid per-observation native heap allocations. Eligible dense, nearly complete full-covariance fits can use screened complete-minus-missing noise statistics, with observed accumulation as the fallback. The screen retains observed zeros and covariance cross terms. These changes preserve the numerical model; no universal speedup or peak-memory bound is claimed.
Historical full cost traces remain the default for PRMS selection. Explicit endpoint-only diagnostics avoid those traces when no requested stopping rule requires them. Coarse configuration recommendations no longer enable relative cost-change/composite stopping; this does not certify posterior stability. Sequential first-minimum selection has its own explicit rule and is distinct from exhaustive minimum and one-standard-error selection.
Thread tuning measures representative covariance/layout work. Opt-in execution profiles retain machine, allocation, build, BLAS and workload fingerprints; incompatible profiles are rejected. Performance CI remains advisory, with timing and allocation evidence separate from numerical parity.
Supported artifacts and release gates¶
| Component | Qualification requirement |
|---|---|
| Python | CPython 3.11, 3.12, 3.13 and 3.14; free-threaded builds are excluded |
| scikit-learn | Runtime >=1.8; native contracts and installed-wheel docs tested on 1.8.0 and 1.9.1 |
| Wheels | All four Python versions on Linux x86_64, macOS arm64 and Windows amd64: twelve wheels |
| Source archive | Install the actual archive, run its extracted tests/API examples and build/verify its strict site |
| Runtime arrays | NumPy and SciPy sparse; pandas through data, Polars 2 through polars, plotting through plot |
| Numerical checks | Independent numerical references, native allocation contracts and actual Octave parity |
From the release checkout:
uv sync --extra dev --extra plot --extra docs
uv run python scripts/check_release_metadata.py --tag v0.5.0
just ci
uv run python scripts/check_numerical_reference.py
uv run python scripts/check_sparse_allocations.py
just docs-check
just build-check
just build-test
The publishing workflow installs the wheel's declared dev,plot extras in each
test environment, including pandas and Polars for the public container contracts.
It tests the installed source archive with scripts/check_sdist_tests.py dist --qualify, requires the complete
advertised artifact matrix and runs strict distribution metadata checks.
The archive includes all three fixed MATLAB reference fixtures; qualification
refuses missing fixtures so the associated regressions cannot silently skip.
A manual workflow dispatch builds and qualifies artifacts without uploading to
PyPI or TestPyPI. Production upload runs only for a published GitHub release,
after the qualification jobs pass.
Frozen scientific installations retain their registered versions and policies until their owners record an adoption decision. This compatibility release does not retune scientific stopping/default policies or change frozen application runs.