--- title: "Migrating analyses and saved models" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Migrating analyses and saved models} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", error = FALSE) library(Riemann) set.seed(2701) ``` The consolidation release changes numerical answers where the previous implementation violated its mathematical contract. Keep the package version and geometry with a saved analysis; retaining old fields does not imply retaining an incorrect answer. ## Existing names and result fields | Existing access | Current behavior | |---|---| | `riem.mean(x)$mean` | Preserved; convergence and objective fields are added. | | `riem.pga(x)$embed` | Preserved; `ndim` is respected up to numerical rank. | | `riem.kmeans(x)$cluster`, `$means`, `$score` | Preserved; starts and termination are recorded. | | `predict(regression, newdata)` | Uses the fitted geometry automatically. | | `geometry = "intrinsic"` on SPD | Resolves to `"affine_invariant"`. | | `geometry = "extrinsic"` on SPD | Resolves to `"log_euclidean"`. | The `riem.kmeans()` default is now Lloyd iteration. Set `algorithm = "MacQueen"` explicitly if that sequential update policy is desired. Its manifold implementation uses the shared Fréchet mean solver; approximate or nonconvex mean solves do not receive a universal monotonicity guarantee. ## Numerical controls are honored Invalid positive-integer controls now produce errors instead of silently rounding or increasing the requested value. Short iteration budgets can produce an unconverged estimate, which must be inspected before reuse. ```{r controls} x <- wrap.spd(list(diag(2), 4 * diag(2))) mean_fit <- riem.mean(x, geometry = "affine_invariant", maxiter = 20, eps = 1e-9) stopifnot(mean_fit$converged) mean_fit$mean stopifnot(max(abs(mean_fit$mean - 2 * diag(2))) < 1e-7) invalid <- tryCatch(riem.mean(x, maxiter = 0), error = identity) stopifnot(inherits(invalid, "error")) conditionMessage(invalid) ``` The mean of `I` and `4 I` is `2 I` under the affine-invariant metric. Earlier iteration-scale errors could cycle in this case. The regression suite now includes independent mathematical answers, together with checks of actual implementation paths. ## Old regression objects without geometry An old object may contain observations, responses, and a bandwidth but lack the geometry used to fit it. These values cannot identify the missing choice. Refit using the original recorded geometry. For a one-time prediction, an explicit original geometry is accepted with a warning; it is the caller's responsibility to recover that information from the analysis record. ```{r legacy-regression} x <- wrap.spd(lapply(c(1, 2, 4, 8), function(a) diag(c(a, 1)))) y <- c(0, 1, 0.5, 2) fit <- riem.m2skreg(x, y, geometry = "log_euclidean", bandwidth = 0.5) legacy <- fit legacy$geometry <- NULL legacy$schema_version <- NULL missing_geometry <- tryCatch(predict(legacy, x), error = identity) stopifnot(inherits(missing_geometry, "error")) conditionMessage(missing_geometry) recovered <- predict(legacy, x, geometry = "log_euclidean") stopifnot(isTRUE(all.equal(recovered, predict(fit, x)))) ``` The warning in this example is deliberate. A saved modern model rejects a different geometry at prediction time; refit explicitly to compare another metric. ```{r incompatible-geometry} changed_geometry <- tryCatch(predict(fit, x, geometry = "affine_invariant"), error = identity) stopifnot(inherits(changed_geometry, "error")) conditionMessage(changed_geometry) ``` ## Refit old tangent and clustering objects An old PGA result with only `center` and `embed` does not contain the loadings, coordinate convention, or offset needed to transform new observations. Refit it from the original training observations. Similarly, old clustering lists should be refitted before using the new prediction interface; their geometry cannot be reliably inferred from centers alone. ```{r refit-pca} training <- wrap.euclidean(rbind(c(0, 0), c(1, 0), c(0, 1), c(1, 2))) pca <- riem.pga(training, ndim = 2) newdata <- wrap.euclidean(matrix(c(0.5, 0.8), 1)) predict(pca, newdata) riem.reconstruct(pca, predict(pca, newdata))$data[[1]] ``` Retain the order and labels of features, channels, and landmarks. The wrapper and fitted contracts check recorded names, but they cannot detect an undocumented semantic change to an unnamed column. ## Domain changes are explicit Indefinite matrices are not SPD observations. Ill-conditioning and positive definiteness are separate issues; adding a ridge or clipping eigenvalues changes the data and belongs in the recorded preprocessing. Sphere zero vectors cannot be normalized. Landmark analysis removes location and scale and uses an orthogonal quotient that permits reflections; verify that this matches the intended question. Some additional manifold families remain available with an `audit_pending` capability status. That label is not a claim of comprehensive validation. Restrict scientific conclusions to the operations and domains actually checked in the analysis, and retain diagnostics and session information. ```{r session} sessionInfo() ```