The package contains covariance
matrices and landmark configurations that can illustrate complete fitted
workflows. These examples are descriptive. Source provenance and the
meaning of observations limit the scientific claims they can support.
The separate write-JSS-Riemann/ writing workspace contains
replication/code.R, which separately regenerates full data
validation, model objects, figures, tables, and an output manifest.
The arrays contain 29 male and 30 female configurations with eight
corresponding landmarks in two dimensions. Their exact upstream mapping
was checked against shapes 1.2.8: reorder
gorm.dat and gorf.dat by
c(1, 5, 4, 3, 2, 8, 7, 6) on the landmark dimension,
retaining coordinate and individual order. The shapes
manual attributes these data to Paul O’Higgins and cites O’Higgins
and Dryden (1993), Journal of Human Evolution 24, 183–205. The
separate writing workspace includes the executable
maintenance/verify-gorilla-provenance.R
array-correspondence verification script.
The workflow analyzes shape after removing location and scale. Its quotient uses all orthogonal transformations, including reflections. This choice is explicit: orientation-preserving shape or original skull size would ask a different question.
data(gorilla)
as_list <- function(a) lapply(seq_len(dim(a)[3]), function(i) a[, , i])
raw <- c(as_list(gorilla$male), as_list(gorilla$female))
group <- factor(c(rep("male", 29), rep("female", 30)), levels = c("male", "female"))
shapes <- wrap.landmark(raw)
shape_fit <- riem.pga(shapes, ndim = 2, geometry = "shape_orthogonal",
maxiter = 300, eps = 1e-8)
stopifnot(shape_fit$diagnostics$converged)
summary(shape_fit)
#> Variance explained in the fitted tangent representation
#> PC1 PC2
#> variance 0.001433009 0.0005266715
#> proportion 0.460481632 0.1692401304
#> cumulative 0.460481632 0.6297217626The retained tangent variance is 63.0%. Sex labels describe this sample; the example does not perform a population test or estimate a causal or biological effect.
plot(shape_fit$embed, col = c("#3565a0", "#bd5845")[as.integer(group)], pch = 19,
xlab = "Tangent PC1", ylab = "Tangent PC2")
legend("topleft", levels(group), col = c("#3565a0", "#bd5845"), pch = 19, bty = "n")Verify that the model uses its trained frame when new batches are wrapped. This check covers positive scaling, translation, rotation, reflection, and single-observation prediction.
angle <- 0.6
rotation <- matrix(c(cos(angle), sin(angle), -sin(angle), cos(angle)), 2)
transformed <- lapply(raw, function(a) sweep(2.3 * a %*% rotation, 2, c(30, -5), "+"))
reflected <- lapply(raw, function(a) a %*% diag(c(-1, 1)))
checks <- c(
location_scale_rotation = max(abs(predict(shape_fit, wrap.landmark(transformed)) - shape_fit$embed)),
reflection = max(abs(predict(shape_fit, wrap.landmark(reflected)) - shape_fit$embed)),
singleton = max(abs(do.call(rbind, lapply(raw, function(a) {
predict(shape_fit, wrap.landmark(list(a)))
})) - shape_fit$embed))
)
stopifnot(all(checks < 1e-7))
checks
#> location_scale_rotation reflection singleton
#> 2.151057e-16 0.000000e+00 2.272488e-16Reconstruct a small variation along the first component. Landmark numbers indicate stored correspondences; no anatomical names or outlines are inferred.
scores <- matrix(0, 3, 2)
scores[, 1] <- c(-2, 0, 2) * sqrt(shape_fit$variance[1])
mode <- riem.reconstruct(shape_fit, scores)$data
plot(mode[[2]], asp = 1, pch = 19,
xlim = range(vapply(mode, function(a) a[, 1], numeric(8))),
ylim = range(vapply(mode, function(a) a[, 2], numeric(8))),
xlab = "Trained preshape coordinate 1",
ylab = "Trained preshape coordinate 2")
points(mode[[1]], col = "#3565a0", pch = 1)
points(mode[[3]], col = "#bd5845", pch = 2)
text(mode[[2]], labels = seq_len(8), pos = 3, cex = 0.7)
legend("bottomleft", c("-2 tangent SD", "reference", "+2 tangent SD"),
col = c("#3565a0", "black", "#bd5845"), pch = c(1, 19, 2), bty = "n")These reconstructions remain in the supported regular local shape neighborhood. Singular alignments and reconstructions outside that chart are explicit errors, not additional validated cases. Full numerical records and both component-mode plots are generated by the separate replication entry point.
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] Riemann_0.2.0 rmarkdown_2.32
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 xfun_0.61 bslib_0.12.0
#> [4] ggplot2_4.0.3 ks_1.15.3 lattice_0.23-1
#> [7] bitops_1.1-0 vctrs_0.7.3 tools_4.6.1
#> [10] Rdpack_2.6.6 generics_0.1.4 parallel_4.6.1
#> [13] cluster_2.1.8.3 highs_1.14.0-2 fds_1.9
#> [16] rstiefel_1.0.1 Matrix_1.7-6 KernSmooth_2.23-27
#> [19] checkmate_2.3.4 RColorBrewer_1.1-3 S7_0.2.2
#> [22] scatterplot3d_0.3-45 maotai_0.3.0 lifecycle_1.0.5
#> [25] compiler_4.6.1 farver_2.1.2 CVXR_1.9.2
#> [28] RcppDE_0.1.9 codetools_0.2-20 htmltools_0.5.9
#> [31] sys_3.4.3 buildtools_1.0.0 rainbow_3.8
#> [34] sass_0.4.10 RCurl_1.98-1.20 gsignal_0.3-7
#> [37] yaml_2.3.12 gmp_0.7-5.1 pracma_2.4.6
#> [40] jquerylib_0.1.4 MASS_7.3-66 T4transport_0.2.0.9002
#> [43] clarabel_0.11.3 cachem_1.1.0 ADMM_0.3.4
#> [46] dbscan_1.2.6 iterators_1.0.14 Rdimtools_1.1.5
#> [49] mclust_6.1.3 foreach_1.5.2 RSpectra_0.16-2
#> [52] digest_0.6.39 Rtsne_0.17 mvtnorm_1.4-2
#> [55] maketools_1.3.2 splines_4.6.1 pcaPP_2.0-5
#> [58] fastmap_1.2.0 grid_4.6.1 colorspace_2.1-3
#> [61] cli_3.6.6 scales_1.4.0 backports_1.5.1
#> [64] DEoptim_2.2-8 scs_3.2.7 otel_0.2.0
#> [67] deSolve_1.42 RANN_2.6.3 fastcluster_1.3.0
#> [70] lpSolve_5.6.23 evaluate_1.0.5 knitr_1.52
#> [73] rbibutils_2.4.1 doParallel_1.0.17 T4cluster_0.1.4
#> [76] rlang_1.3.0 Rcpp_1.1.2 hdrcde_3.5.0
#> [79] glue_1.8.1 fda_6.3.0 osqp_1.0.0
#> [82] mclustcomp_0.3.5 jsonlite_2.0.0 R6_2.6.1