Follow-up to #255. tf_crosscov(fm) and tf_crosscor(fm) for tf_mv are not a single function call — there are two distinct semantics, both useful, both worth supporting.
Option A — intra-tf_mv between components
Given fm with components (x_1, …, x_d), return the d × d matrix of cross-covariance surfaces K_{ij}(s, t) = Cov(x_i(s), x_j(t)). The natural output shape is a 2-D structure of tfd surfaces (or a tf_mv of surfaces if/when surface support exists), or simply the d × d matrix-valued operator. Diagonal = within-component auto-covariance; off-diagonal = cross-covariances.
Mathematically clean. The output shape ("a matrix of cov surfaces") is awkward in the current tf representation but tractable as a matrix of tfd lists (rownames/colnames = component names).
Option B — inter-tf_mv between two arguments
tf_crosscov(fm1, fm2) returns the cross-covariance between two tf_mv vectors. Either:
- per-pair
(fm1$x_i, fm2$x_j) → d_1 × d_2 matrix of cov surfaces, or
- joint over the stacked vectors — but that collapses to a
(d_1 + d_2) × (d_1 + d_2) block matrix, which subsumes Option A when fm1 == fm2.
Recommendation
Implement both via the existing single-vs-two-argument dispatch pattern:
tf_crosscov(fm) # intra: d × d matrix of cov surfaces (Option A)
tf_crosscov(fm1, fm2) # inter: d_1 × d_2 matrix (Option B)
tf_crosscor follows by standardizing with the diagonal. Both rely on a sensible output type for "matrix-of-cov-surfaces" — start with matrix containers of tfd and revisit when surface support exists.
Tests should pin
tf_crosscov(fm)[i, j] == tf_crosscov(fm$x_i, fm$x_j) for the univariate single-pair case
- Symmetry:
tf_crosscov(fm)[i, j](s, t) == tf_crosscov(fm)[j, i](t, s)
- Diagonal:
tf_crosscov(fm)[i, i] == tf_acov(fm$x_i) (or whatever the univariate auto-cov verb is)
tf_crosscov(fm, fm) == tf_crosscov(fm)
Filed as follow-up to #255 (tf_mv inheritance contract) and the June-2026 ground-up review.
Follow-up to #255.
tf_crosscov(fm)andtf_crosscor(fm)fortf_mvare not a single function call — there are two distinct semantics, both useful, both worth supporting.Option A — intra-
tf_mvbetween componentsGiven
fmwith components(x_1, …, x_d), return thed × dmatrix of cross-covariance surfacesK_{ij}(s, t) = Cov(x_i(s), x_j(t)). The natural output shape is a 2-D structure oftfdsurfaces (or atf_mvof surfaces if/when surface support exists), or simply thed × dmatrix-valued operator. Diagonal = within-component auto-covariance; off-diagonal = cross-covariances.Mathematically clean. The output shape ("a matrix of cov surfaces") is awkward in the current
tfrepresentation but tractable as amatrixoftfdlists (rownames/colnames = component names).Option B — inter-
tf_mvbetween two argumentstf_crosscov(fm1, fm2)returns the cross-covariance between twotf_mvvectors. Either:(fm1$x_i, fm2$x_j)→d_1 × d_2matrix of cov surfaces, or(d_1 + d_2) × (d_1 + d_2)block matrix, which subsumes Option A when fm1 == fm2.Recommendation
Implement both via the existing single-vs-two-argument dispatch pattern:
tf_crosscorfollows by standardizing with the diagonal. Both rely on a sensible output type for "matrix-of-cov-surfaces" — start withmatrixcontainers oftfdand revisit when surface support exists.Tests should pin
tf_crosscov(fm)[i, j] == tf_crosscov(fm$x_i, fm$x_j)for the univariate single-pair casetf_crosscov(fm)[i, j](s, t) == tf_crosscov(fm)[j, i](t, s)tf_crosscov(fm)[i, i] == tf_acov(fm$x_i)(or whatever the univariate auto-cov verb is)tf_crosscov(fm, fm) == tf_crosscov(fm)Filed as follow-up to #255 (
tf_mvinheritance contract) and the June-2026 ground-up review.