---
title: "Animating metric MDS: paraboloid and saddle"
output:
rmarkdown::html_vignette:
toc: true
math_method: mathml
vignette: >
%\VignetteIndexEntry{Animating metric MDS: paraboloid and saddle}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include=FALSE}
library(grip)
options(rgl.useNULL = TRUE)
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
source(system.file("scripts", "metric-mds-animation.R", package = "grip"),
local = TRUE)
```
How does a random cloud become a curved surface when only its pairwise
distances are known? The SGD backend of `metric.mds()` adjusts a pair of
points at a time. Its optional **update trace** lets us inspect those actual
states and animate the reconstruction.
This example reconstructs a paraboloid and a saddle from the ambient distances
between 250 points. Both have two intrinsic dimensions, but preserving their
straight-line distances generally requires three embedding dimensions.
Distances along the surface would define a different reconstruction problem.
The vignette uses the tracing interface in the development version of grip
(after 0.2.0). It rebuilds the fits from public R calls, without a separate
instrumented solver or saved fitting results. The optional **ivue** and **rgl**
packages provide the interactive view; numerical examples still run without
them. See [Metric MDS](metric-mds-backends.html) for other weighting choices.
## Sample the same points on two surfaces
On the unit disk, take \(z=x^2+y^2\) for the paraboloid and
\(z=x^2-y^2\) for the saddle. Both have area element
\(\sqrt{1+4r^2}\,r\,dr\,d\theta\). To sample uniformly over surface area, draw
\(U\) uniformly on \([0,1]\), an independent uniform angle, and use
\[
r=\sqrt{\frac{\{1+U(5^{3/2}-1)\}^{2/3}-1}{4}}.
\]
Thus the same sampled \(x,y\) positions give a surface-area sample on either
surface. Only heights and target distances change.
```{r sample}
set.seed(20261020)
n <- 250L
u <- runif(n)
theta <- runif(n, 0, 2*pi)
r <- sqrt(((1 + u*(5^(3/2) - 1))^(2/3) - 1)/4)
paraboloid <- cbind(x = r*cos(theta), y = r*sin(theta), z = r^2)
saddle <- paraboloid
saddle[, "z"] <- saddle[, "x"]^2 - saddle[, "y"]^2
stopifnot(identical(paraboloid[, 1:2], saddle[, 1:2]))
```
We fit all \(250\times249/2=31{,}125\) unordered pairs. The view draws only
1,000 sampled chords to keep the surface visible; this display subset does
not change the fit.
## Choose the target error and the initial cloud
Let \(d_{ij}>0\) be a target distance and \(\widehat d_{ij}\) the distance in
the current embedding. We display the mean squared relative error
\[
S=\frac{1}{m}\sum_{i