Skip to content

v0.21.1: TT _dim_order cluster + open issues + perf#23

Merged
0xC000005 merged 16 commits intomainfrom
v0.21.1-dim-cluster
Apr 27, 2026
Merged

v0.21.1: TT _dim_order cluster + open issues + perf#23
0xC000005 merged 16 commits intomainfrom
v0.21.1-dim-cluster

Conversation

@0xC000005
Copy link
Copy Markdown
Owner

Summary

Closes the v0.20+v0.20.1 _dim_order cluster on ChebyshevTT surfaced by ultrareview, plus three open follow-up issues, plus two perf hoists.

Critical/Important fixes (TT _dim_order cluster)

  • roots/minimize/maximize validate fixed against user-frame domain (was storage-frame; under non-uniform domains + non-identity _dim_order could raise misleading errors or accept invalid inputs)
  • inner_product raises ValueError on mismatched _dim_order (was silently miscomputing Frobenius product)
  • get_evaluation_points returns columns in user-frame order (was storage order, breaking eval(get_evaluation_points()[i]) round-trip)

Open issues closed

  • #19eval_multi thread-safety: structural fix via _eval_storage_frame private helper (also reroutes _fd_* helpers)
  • #20integrate error message: now references user-frame dim index
  • #22_algebra._check_compatible: now uses np.allclose (handles tuple-vs-list mixed domain syntax)

Performance

  • _calculus._optimize_1d vectorized — used by all four classes' minimize/maximize
  • vectorized_eval_batch derivative-matrix hoist (with moveaxis correction for non-trailing axes) — speedup for batch derivative evaluations

Deferred

  • ChebyshevTT.sobol_indices deferred to v0.22 (native TT contraction implementation exceeded v0.21.1 time budget)

Tests

~25 new tests across test_calculus_completion.py, test_v0201_dim_threading.py, test_tensor_train.py, test_calculus.py, test_algebra.py, test_barycentric.py. Total project: ~1133 passing.

Test plan

  • CI green on all 4 Python versions
  • uv run python compare_v0211_dim_cluster.py shows all [OK ]
  • mkdocs build --strict clean
  • uv build produces 0.21.1 wheel + sdist

🤖 Generated with Claude Code

0xC000005 and others added 10 commits April 27, 2026 12:06
Raise ValueError with reorder() hint when self._dim_order != other._dim_order
instead of silently computing a meaningless Frobenius product. Mirrors the
v0.20.1 binary algebra behavior on _check_compatible_tt mismatches.

Closes ultrareview Critical finding.
Replace exact == / != on .domain and .n_nodes with np.allclose / np.array_equal
on coerced arrays. Tolerates tuple-of-tuples vs list-of-lists syntax that
silently arises in scalar-mul (which normalizes via [list(b) for b in domain]).

Closes issue #22.
Permute columns by inverse _dim_order before returning so that
eval(get_evaluation_points()[i]) round-trips for any TT regardless of
storage permutation. Matches Approximation/Spline/Slider behavior.

Closes ultrareview Important finding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add _user_frame_domain() private helper that returns self.domain permuted
into user-frame order. The three v0.21 methods now pass this user-frame
view to _calculus._validate_calculus_args instead of the raw storage-frame
self.domain.

Pre-fix: under non-identity _dim_order with non-uniform per-dim domains,
validation referenced the wrong domain. Tests pass before the fix only
because uniform domains masked the difference.

Closes ultrareview Critical finding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add optional dim_labels= parameter to _normalize_bounds. ChebyshevTT.integrate
passes user-frame dims_sorted as dim_labels so out-of-domain bounds errors
reference the dim the user passed rather than the storage-frame index.

Helper stays user-frame-naive otherwise.

Closes #20.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ssue #19)

Extract _eval_storage_frame(point_storage, deriv_storage) private helper
that takes already-permuted coords. eval() permutes user→storage once at
entry and calls _eval_storage_frame; eval_multi() permutes once and calls
the helper N times for each derivative_order.

Drops the try/finally self._dim_order mutation entirely. Eliminates the
race rather than papering over it with a lock.

The FD machinery (_fd_single_dim, _fd_cross_deriv, _fd_nested) was
updated to call _eval_storage_frame instead of self.eval, since the
points it operates on are already in storage frame; routing through
self.eval would re-permute and break correctness once the saved-state
trick is removed.

Closes #19.
Replace the Python list comprehension over candidates with a single
vectorized barycentric evaluation (BLAS GEMV pattern). _optimize_1d is
the canonical 1-D optimizer used by all four classes' minimize/maximize
methods; v0.21 routed Slider/TT min/max through it, making the perf
hoist worthwhile.

Bit-identical results — non-regression tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…atch loop

The differentiation matrix (D_T) matmul is point-independent — applying
it once to self.tensor_values before the per-point loop, then doing only
the barycentric reduction inside the loop, produces identical results
with substantial speedup for batch derivative evaluations.

Each D_T[d] is applied along axis d of the full tensor (via moveaxis to
last, matmul, moveaxis back) to correctly match the per-dim interleaved
semantics of vectorized_eval. ChebyshevSpline.eval_batch (which delegates
per-piece) inherits the speedup.
Demonstrates each fix in the TT _dim_order cluster with a non-uniform
domain and explicit reorder() — the configuration that v0.20.1/v0.21.0
test coverage masked.

Native TT sobol_indices deferred to v0.22; not included in this demo.
Add non-uniform-domain validation note to user-guide.
Bump version to 0.21.1.
CHANGELOG entry covering all 6 fixes + 2 perf wins, with sobol_indices
deferred to v0.22.
CLAUDE.md updated with new test count and v0.21.1 architecture line.
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 27, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 98.03922% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pychebyshev/barycentric.py 92.59% 2 Missing ⚠️
src/pychebyshev/_sensitivity.py 98.18% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

0xC000005 and others added 6 commits April 27, 2026 13:05
… sites

Final cumulative review (M1) noted that ChebyshevTT.inner_product and
the binary-algebra _check_compatible_tt path also use exact == on
self.domain, paralleling the issue #22 fix in _algebra._check_compatible.
Apply the same np.allclose pattern to both TT sites for consistency
with the v0.21.1 fix.

(M2) Add compare_v0211_dim_cluster.py to the CLAUDE.md benchmark roster.
Compute first-order + total-order Sobol indices by contracting through
the TT coefficient cores in O(d * n * r^2) time. Cross-validated against
ChebyshevApproximation.sobol_indices() on dense reconstructions.

Closes the v0.21.1 sobol_indices parity item (originally deferred but
attempted on user request).
Appends test_non_uniform_domain_after_reorder to TestTTSobolParity,
covering the exact configuration that masked v0.21.0 _dim_order bugs:
non-uniform per-dim domains [(-1,1), (-2,2), (-3,3)] combined with a
non-identity _dim_order (reorder([2,0,1])). Verifies TT sobol keys stay
in user-frame after reorder, matching ChebyshevApproximation reference.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Issue 2)

Adds private _apply_derivative_passes(tensor, derivative_order) that
applies differentiation-matrix passes along each axis of the full
coefficient tensor using np.moveaxis. Used by vectorized_eval_batch to
replace the duplicated ~10-line derivative-hoist block, making the batch
path self-documenting. vectorized_eval inlines its own per-axis logic
(reduces axes as it goes, so the full-tensor moveaxis path doesn't apply
there) and is left unchanged to avoid unneeded churn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r sobol (Issue 3)

Replaces d independent full self-inner-product loops for total-order
computation with precomputed L[k] (left partial, dims 0..k-1) and R[k]
(right partial, dims k..d-1) matrices. For each dim j, combines L[j],
the alpha_j=0 core slice, and R[j+1] via a single einsum instead of
re-running all d cores. Reduces from O(d^2*n*r^2) to O(d*n*r^2).
Existing TestSobolFromTTCores and TestTTSobolParity tests continue to
pass at 1e-9 (2-D) and 1e-7 (3-D) tolerances.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@0xC000005 0xC000005 merged commit 758aa46 into main Apr 27, 2026
10 checks passed
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