Skip to content

Document model inversion, and pin the constants the book quotes - #478

Merged
kgdunn merged 2 commits into
mainfrom
claude/pid-book-opls-code-xzm6ef
Jul 29, 2026
Merged

Document model inversion, and pin the constants the book quotes#478
kgdunn merged 2 commits into
mainfrom
claude/pid-book-opls-code-xzm6ef

Conversation

@kgdunn

@kgdunn kgdunn commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Follow-up to #470, which added PLS.invert() and OPLS. Companion to the
pid-book PR kgdunn/pid-book#259, which writes the same material up as a chapter.

Documentation

PLS.invert() and OPLS landed with docstrings but no narrative page, so the
reasoning behind them lived only in the book. docs/user_guide/model_inversion.rst
covers:

  • inverting a PLS model, and why the answer is a set of designs rather than one;
  • walking the null space with null_space_coordinates, and what rising
    Hotelling's T-squared along that walk means;
  • why inversion can need more components than prediction does, since it has to
    describe the X-space well enough to map a score back into it;
  • the O-PLS decomposition and why, for a single response, its orthogonal space
    is the same linear space as the PLS null space;
  • how well the null-space direction is actually determined, which for the
    cheddar-cheese example is not well at all;
  • why a multivariate specification region is not the box of per-input ranges
    that summarises it.

It is linked from the hidden toctree in multivariate.rst, beside pca, pls,
tpls and multiblock.

Tests

These close a real gap rather than adding coverage for its own sake.

Most numbers in the book's worked example are printed by code blocks a reader
can run, so a change in this library would be visible there. A handful are
quoted in prose without appearing in any output, and nothing would have caught
a silent change to them:

Quantity Value
Hotelling's T-squared limits, 95% and 99% 7.36, 12.14
SPE limit, 99% 1.60
Score norm at the direct-inversion solution 0.281
Score norm at the -1 and +1 steps 1.039
Step at which T-squared is least -0.103
PLS first weight against its own loading 5.49 degrees
O-PLS predictive weight against its loading 0.31 degrees
PLS and O-PLS regression coefficients agree to 1.4e-13
O-PLS split of the sum of squares in X 68.7 / 18.3 / 13.0

The tolerances match the precision the text quotes, so a failure means a
sentence in the book needs rewriting, not that a digit moved far downstream.
Two of the tests check identities rather than only values: that
||tau_DI + s g||^2 == ||tau_DI||^2 + s^2 for the steps taken, and that
w'p == 1, which is what makes p - w a plain subtraction.

The last test pins the specification-region result: of the eight corners of
the box of three ranges, exactly two predict an acceptable taste, both of those
are beyond the T-squared limit, and therefore none is an acceptable lot.

Verification

ruff check and mypy src/process_improve clean. The 26 tests in this file and
test_multivariate_opls.py pass.

The wider suite has pre-existing failures in this sandbox from missing optional
extras (seaborn, ridgeplot, and the DOE solver); they reproduce identically
on main with this branch stashed, and CI installs --all-extras.

Version is a patch bump, 1.62.0 to 1.62.1: documentation and tests only, no
behaviour change. CITATION.cff and CHANGELOG.md updated in step.


Generated by Claude Code

claude added 2 commits July 28, 2026 22:13
The inversion and O-PLS APIs landed with docstrings but no narrative page, so
the reasoning behind them lived only in the book. The new user-guide page
covers PLS.invert, walking the null space, why inversion can need more
components than prediction does, the equivalence with the O-PLS orthogonal
space, how well the null-space direction is actually determined, and why a
specification region is not the box of per-input ranges that summarises it.

The tests close a real gap. Most numbers in the book's worked example are
printed by code blocks a reader can run, so a change here would show up there.
A handful are quoted in prose without appearing in any output: the T-squared
and SPE limits, the score norms either side of the direct-inversion solution,
the step at which T-squared is least, the angle between each weight and its
own loading before and after the orthogonal variation is removed, the
agreement between the PLS and O-PLS regression coefficients, and the split of
the sum of squares in X. Nothing would have caught a silent change to those.
The tolerances match the precision the text quotes, so a failure means a
sentence needs rewriting rather than a digit having moved far downstream.

Version is a patch bump: documentation and tests only, no behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DsTypY4FcRbrXRxorb9raz
The test skipped on `mcp`, but newer releases ship a top-level `mcp` package
without `mcp.server.fastmcp`. With every extra installed, as CI does, the
coarse guard did not fire and the test failed on the import instead of
skipping. The sibling test in test_mcp_server.py already guards on the
submodule; this matches it.

Not caused by this branch: the test has been unchanged since #389 and fails
the same way on main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DsTypY4FcRbrXRxorb9raz
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kgdunn
kgdunn merged commit 2ab876f into main Jul 29, 2026
14 checks passed
@kgdunn
kgdunn deleted the claude/pid-book-opls-code-xzm6ef branch July 29, 2026 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants