Skip to contents

Represent observations and choose their geometry

Rows of support are atoms, and mass belongs to one distribution. Weights across distributions instead determine their importance in a collection. Constructors normalize these two kinds of weights separately.

x <- ot_measure(rbind(c(0, 0), c(1, 0), c(0, 2)), c(1, 2, 1))
y <- ot_measure(rbind(c(0, 0), c(0, 1), c(-2, 0)), c(1, 2, 1))
exact <- ot_distance(x, y, method = "exact", return_plan = TRUE)
ot_inspect(exact)
#> Transport report | finite | unregularized_transport 
#> Producer: ot_distance 
#> Status: SUCCESS ( optimal_pivot_condition )
#>             distance       transport_cost  transport_cost_root 
#>             1.414214             2.000000             1.414214 
#> wasserstein_distance 
#>             1.414214 
#> Scope: reported stopping criterion only; interpret its reason and available checks

Exact coordinate transport uses the supplied locations. Entropic transport optimizes a different objective, consisting of a transport component and an entropy term. The full value can be negative and is not a metric.

entropic <- ot_distance(x, y, method = "sinkhorn", epsilon = .1)
#> Warning: Transport computation: iteration_limit (marginal_tolerance_not_met).
ot_inspect(entropic)
#> Transport report | finite | entropic_transport 
#> Producer: ot_distance 
#> Status: ITERATION_LIMIT ( marginal_tolerance_not_met )
#>              distance        transport_cost   transport_cost_root 
#>              1.414209              1.999988              1.414209 
#> regularized_objective 
#>              1.761338 
#> Scope: reported stopping criterion only; interpret its reason and available checks

For an approximation based on projections, save the actual directions. Directions supplied as rows are normalized by the function. Reusing them makes numerical comparisons meaningful; a matching seed alone need not produce the same directions in another language. A finite direction set can define only a pseudometric: distinct measures may have zero sliced value.

directions <- rbind(c(1, 0), c(0, 1), c(1, 1))
sliced <- swdist(x, y, directions = directions)
ot_inspect(sliced)
#> Transport report | sliced | finite_direction_sliced_wasserstein 
#> Producer: swdist 
#> Status: SUCCESS ( all_finite_1d_problems_solved )
#>  distance 
#> 0.9574271 
#> Scope: finite projected problems solved; sphere-integration accuracy is not certified

Alignment and relational geometry

Procrustes-Wasserstein comparison optimizes orthogonal alignment, including reflections. It does not automatically center, translate, or rescale inputs. Gromov-Wasserstein comparison instead uses within-object dissimilarities. Use Euclidean distances here: the GW squared loss supplies its own square.

aligned <- pwdist(x, y)
relational <- gwdist(as.matrix(dist(x$support)),
                     as.matrix(dist(y$support)),
                     wx = x$mass, wy = y$mass, maxiter = 100)
ot_inspect(aligned)
#> Transport report | procrustes | procrustes_wasserstein_local_comparison 
#> Producer: pwdist 
#> Status: SUCCESS ( block_objective_tolerance )
#>       distance transport_cost      objective 
#>              0              0              0 
#> Scope: none; alternating block objective stopping is local
ot_inspect(relational)
#> Transport report | gromov | gromov_wasserstein_squared_discrepancy 
#> Producer: gwdist 
#> Status: SUCCESS ( first_order_gap )
#>  distance objective 
#>         0         0 
#> Scope: none; first-order stopping is not global optimality

A local stopping condition is not a global optimization certificate. Raw magnitudes from distinct objectives should not be used as a scoreboard for choosing a geometry. In the accompanying shape application, centering and RMS-radius scaling are explicit choices that remove position and size.

Gaussian parameters and distribution summaries

Gaussian objects avoid artificial sampling. In one dimension, W2 geometry is Euclidean in mean and standard deviation; a barycenter averages those coordinates separately. A Gaussian-family median minimizes a different objective within the declared family.

inputs <- list(ot_gaussian(0, 1), ot_gaussian(2, 4), ot_gaussian(8, 1))
bary <- ot_gaussian_summary(inputs, weights = c(2, 2, 1))
med <- ot_gaussian_summary(inputs, target = "median", weights = c(2, 2, 1))
bary$estimate
#> Gaussian probability measure in 1 dimension(s)
#> Covariance domain: nonnegative variance 
#> Mean: 2.4
med$estimate
#> Gaussian probability measure in 1 dimension(s)
#> Covariance domain: nonnegative variance 
#> Mean: 2
ot_inspect(med)
#> Transport report | gaussian | gaussian_family_median 
#> Producer: ot_gaussian_summary 
#> Status: SUCCESS ( collision_optimality )
#> objective 
#>   2.11098 
#> Scope: reported stopping criterion only; interpret its reason and available checks

Multivariate covariance matrices must be strictly positive definite. The package does not add a ridge or silently project invalid covariances. General multivariate medians retain local-optimization qualifications.

Finite summaries use ot_summary() with an explicit feasible set. Scalar finite distributions support exact quantile representations. Fixed-support summaries optimize masses; free-support fixed-mass summaries optimize locations. These are distinct restrictions, not interchangeable solver settings.

collection <- ot_collection(lapply(c(0, 0, 0, 2, 8), ot_measure))
fit <- ot_summary(collection, target = "median")
ot_inspect(fit)
#> Transport report | finite | median 
#> Producer: ot_summary 
#> Status: SUCCESS ( collision_optimality )
#> objective 
#>         2 
#> Scope: reported stopping criterion only; interpret its reason and available checks

Read the available evidence

ot_inspect() extracts available metadata without recomputing a result. Its components identify the problem, numerical values, termination scope, checks, approximation, history and settings. Missing information stays missing. Inner failures, iteration limits and rejected steps remain visible. The original result still supplies the family-specific estimate or plan.

report <- ot_inspect(aligned)
stopifnot(identical(report, unserialize(serialize(report, NULL))))
names(report)
#> [1] "problem"       "values"        "termination"   "checks"       
#> [5] "approximation" "history"       "settings"

Constructors, plotting helpers, fiedler() and the descriptive resampling helper wassboot() are outside this accessor. Inspect individual elements of a multi-time interpolation result rather than the enclosing list.