| Title: | Graph Drawing with Intelligent Placement (GRIP) |
|---|---|
| Description: | Implements GRIP multiscale graph layout with a unified choice between hop-count and geometry-aware edge-length graph metrics in 2D and 3D. Provides layout scoring, candidate comparison, multiscale trace diagnostics, synthetic graph families, and advanced experimental geodesic-KK utilities for weighted-layout evaluation and polish. Based on Gajer and Kobourov (2002) <doi:10.7155/jgaa.00052> and Gajer, Goodrich and Kobourov (2004) <doi:10.1016/j.comgeo.2004.03.014>. Includes derived graph datasets from the SuiteSparse Matrix Collection, with source attribution and transformation metadata. |
| Authors: | Pawel Gajer [aut, cre], Jonathan Zheng [ctb, cph] (Author and copyright holder of MIT-licensed s_gd2 code adapted for the metric-MDS SGD backend), Daniel Hangan [ctb] (Author of the SGD-MDS implementation in his scikit-learn fork adapted for the metric-MDS SGD backend), The scikit-learn developers [cph] (Copyright holders of BSD-3-Clause code adapted from Daniel Hangan's scikit-learn fork for the metric-MDS SGD backend) |
| Maintainer: | Pawel Gajer <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.2.0.9001 |
| Built: | 2026-09-30 19:40:04 UTC |
| Source: | https://github.com/pgajer/grip |
Fast multiscale graph layouts in 2D and 3D.
Use grip() to draw a graph, then
score.layout() to assess the result.
Open vignette("grip-examples", package = "grip") for a small
complete workflow, or vignette("function-guide", package = "grip")
to choose functions by task. The example below draws a 20-vertex mesh and
prints sampled graph-distance stress: zero means perfect agreement on the
sampled pairs after fitting a common scale, not a certificate for every pair.
Use metric = "hop" for connectivity or
metric = "edge_length" when positive lengths define the graph
metric. See vignette("weighted-grip-intro", package = "grip").
vignette("grip-real-data", package = "grip").
vignette("grip-trace-and-diagnostics", package = "grip").
vignette("synthetic-graph-families", package = "grip").
List available guides with vignette(package = "grip").
Development installations from GitHub include these guides only when built
with build_vignettes = TRUE. The
website also provides rendered guides,
the graph gallery, comparisons, case study, and explorer walkthrough from
the same installed vignette sources. Check
packageVersion("grip") when using development documentation.
The public experimental edge-KK and geodesic-KK helpers provide weighted-layout evaluation and refinement. Choose these through the function guide after trying the main layout, scoring, and tracing workflows.
Vertex indices and counts must be finite integers within the R integer
range. Adjacency must be reciprocal with matching lengths and multiplicity.
Self-loops are rejected; remove them explicitly. Supply either edges/edge.weights or
adj.list/weight.list, not both. Functions accepting a
prepared graph reject additional raw graph inputs; an explicit
n must match the stored vertex count. Rebuild the preparation when
changing topology, vertex order, or edge lengths.
The internal compiled GMDS optimizer, also used by the GMDS exploration
apps, uses at most two CPU threads. With automatic selection
(n.threads = 0), GRIP_GMDS_THREADS can be set to 1 or
2 to choose the thread count before hardware concurrency is consulted.
An explicit positive n.threads overrides the environment variable;
values above two are capped at two. Non-positive or nonnumeric environment
values fall back to hardware-based selection. The R optimization engine is
serial. This setting is not a package-wide control for GRIP layouts or for
third-party numerical libraries.
Maintainer: Pawel Gajer [email protected]
Authors:
Pawel Gajer [email protected]
Other contributors:
Jonathan Zheng (Author and copyright holder of MIT-licensed s_gd2 code adapted for the metric-MDS SGD backend) [contributor, copyright holder]
Daniel Hangan (Author of the SGD-MDS implementation in his scikit-learn fork adapted for the metric-MDS SGD backend) [contributor]
The scikit-learn developers (Copyright holders of BSD-3-Clause code adapted from Daniel Hangan's scikit-learn fork for the metric-MDS SGD backend) [copyright holder]
Gajer, P. and Kobourov, S.G. (2002). GRIP: Graph dRawing with Intelligent Placement. Journal of Graph Algorithms and Applications, 6(3), 203–224. doi:10.7155/jgaa.00052.
Gajer, P., Goodrich, M.T. and Kobourov, S.G. (2004). A multi-dimensional approach to force-directed layouts of large graphs. Computational Geometry, 29(1), 3–18. doi:10.1016/j.comgeo.2004.03.014.
Useful links:
Report bugs at https://github.com/pgajer/grip/issues
edges <- edges.mesh(4, 5) coords <- grip(edges, n = 20, dim = 2, preset = "mesh", seed = 11) plot.layout(coords, edges = edges, pch = 16, main = "A 4 by 5 mesh") quality <- score.layout(coords, edges = edges, n = 20, sample.size.stress = 200, stress.seed = 11, edge.crossings = "never") quality[, c("sampled.stress", "edge.length.cv")]edges <- edges.mesh(4, 5) coords <- grip(edges, n = 20, dim = 2, preset = "mesh", seed = 11) plot.layout(coords, edges = edges, pch = 16, main = "A 4 by 5 mesh") quality <- score.layout(coords, edges = edges, n = 20, sample.size.stress = 200, stress.seed = 11, edge.crossings = "never") quality[, c("sampled.stress", "edge.length.cv")]
build.misf() exposes the maximal independent set filtration already
constructed internally by the GRIP layout engine. The result is graph-first:
you can supply either an edge list plus n, or an adjacency/weight-list
pair.
build.misf( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, num.init = 24L, num.nbrs = 20L, seed = 6L )build.misf( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, num.init = 24L, num.nbrs = 20L, seed = 6L )
edges |
Two-column integer matrix of undirected edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Optional adjacency list (1-based integer vectors). |
weight.list |
Optional positive edge-weight list parallel to |
edge.weights |
Optional positive vector parallel to |
num.init |
Target top-level active-set size used by the current GRIP
MISF builder. The returned highest MISF level has size at most
|
num.nbrs |
Retained local neighborhood budget per MISF level, matching the current GRIP refinement schedule metadata. |
seed |
Optional integer seed passed to the current GRIP graph RNG. |
The current implementation returns the same MISF structure used by GRIP's multiscale layout core. Edge weights are accepted and passed through the underlying graph object, but the current MISF construction itself is driven by the graph topology and hop-distance thresholds rather than weighted shortest-path distances.
An object of class "grip_misf" containing:
Named list V0, V1, ... of nested vertex sets (1-based).
Integer vector giving the highest MISF level containing each vertex.
The internal GRIP MISF order (1-based vertex ids).
Sizes of the nested levels.
Per-level retained neighborhood counts used by the current GRIP engine.
Highest MISF level index.
Size of the highest MISF level.
edges <- edges.mesh(4, 4) misf <- build.misf(edges = edges, n = 16, num.init = 6, seed = 1) misf$misf_size misf$levels[[1L]]edges <- edges.mesh(4, 4) misf <- build.misf(edges = edges, n = 16, num.init = 6, seed = 1) misf$misf_size misf$levels[[1L]]
build.weighted.misf() builds the weighted max-independent-set
filtration used by the weighted GRIP layout core. It is primarily a
diagnostic and benchmarking helper for comparing weighted and combinatorial
hierarchies on the same graph.
build.weighted.misf( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, num.init = 24, num.nbrs = 20, length.normalization = c("median", "mean", "none"), seed = 6 )build.weighted.misf( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, num.init = 24, num.nbrs = 20, length.normalization = c("median", "mean", "none"), seed = 6 )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Parallel list of strictly positive edge lengths. |
edge.weights |
Optional vector of edge lengths for |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of retained local neighbors per level. |
length.normalization |
Global edge-length normalization:
|
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
A list with weighted MISF levels, vertex_depth,
mish_order, misf_size, num_nbrs_schedule,
misf_height, top_level_size, weight_scale, and
length_normalization.
cycle_edges <- edges.cycle(6) cycle_lengths <- seq(0.8, 1.3, length.out = nrow(cycle_edges)) levels <- build.weighted.misf( edges = cycle_edges, n = 6, edge.weights = cycle_lengths, num.init = 3, num.nbrs = 2, seed = 1 )cycle_edges <- edges.cycle(6) cycle_lengths <- seq(0.8, 1.3, length.out = nrow(cycle_edges)) levels <- build.weighted.misf( edges = cycle_edges, n = 6, edge.weights = cycle_lengths, num.init = 3, num.nbrs = 2, seed = 1 )
classical.mds() computes the classical-MDS baseline using
stats::cmdscale() on the graph shortest-path distance matrix and returns a
common "grip_gmds_layout" result.
classical.mds( prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2L, add = FALSE, eig = TRUE, diagnostics = TRUE, scale.mode = c("profiled", "identity", "user"), distance.floor = 1e-08, edge.length.epsilon = 1e-08, band.quantiles = c(1/3, 2/3) )classical.mds( prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2L, add = FALSE, eig = TRUE, diagnostics = TRUE, scale.mode = c("profiled", "identity", "user"), distance.floor = 1e-08, edge.length.epsilon = 1e-08, band.quantiles = c(1/3, 2/3) )
prepared |
Optional all-pairs prepared object returned by
|
edges |
Two-column integer edge matrix used when |
n |
Finite positive integer vertex count. When supplied with a prepared object, it must match the stored graph size. |
adj.list |
Optional adjacency list used when |
weight.list |
Optional edge-weight list parallel to |
edge.weights |
Optional positive edge weights parallel to |
dim |
Target embedding dimension. Values greater than 3 are supported for GMDS and edge-KK workflows. |
add, eig
|
Passed to |
diagnostics |
If |
scale.mode |
Scale policy for edge, path, and chord targets:
|
distance.floor |
Positive floor for relative residuals. |
edge.length.epsilon |
Small stabilizer for fixed-path embedded lengths. |
band.quantiles |
Two quantiles splitting graph distances into short, mid, and long bands. |
A "grip_gmds_layout" object.
Start with vignette("function-guide", package = "grip")
to choose a layout, diagnostic, or reference comparison. List installed
guides with vignette(package = "grip").
cycle_edges <- edges.cycle(6) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) fit <- classical.mds(prepared = prepared, dim = 2)cycle_edges <- edges.cycle(6) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) fit <- classical.mds(prepared = prepared, dim = 2)
compare.layouts() computes layouts for several candidate presets
or parameter lists, optionally expands a local parameter search, scores each
run with score.layout(), and summarizes both quality
metrics and seed-to-seed stability. This is the main real-data workflow for
graphs where no canonical embedding is known.
compare.layouts( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2, candidates = c("default"), search = NULL, clusters = NULL, seeds = 1:3, sample.size.stress = 2000L, sample.size.nonedge = 5000L, edge.crossings = c("auto", "always", "never"), edge.crossings.max.edges = 1000L, score.weights = grip.default.compare.score.weights(), return.layouts = FALSE, disconnected = c("components", "error") )compare.layouts( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2, candidates = c("default"), search = NULL, clusters = NULL, seeds = 1:3, sample.size.stress = 2000L, sample.size.nonedge = 5000L, edge.crossings = c("auto", "always", "never"), edge.crossings.max.edges = 1000L, score.weights = grip.default.compare.score.weights(), return.layouts = FALSE, disconnected = c("components", "error") )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
dim |
Layout dimension (2 or 3). |
candidates |
Either a character vector such as
|
search |
Optional named list describing a grid search over layout
settings. Any of |
clusters |
Optional cluster or community labels used to compute
|
seeds |
Integer seeds used for repeated runs. |
sample.size.stress |
Number of sampled pairs used for
|
sample.size.nonedge |
Number of sampled non-edge pairs used for
|
edge.crossings |
How to compute |
edge.crossings.max.edges |
Edge-count threshold for
|
score.weights |
Optional named numeric vector used to compute
|
return.layouts |
If |
disconnected |
Passed through to |
Procrustes stability is the mean pairwise root-mean-square vertex distance
after centering each layout, scaling it to unit maximum radius, and applying
the optimal orthogonal rotation or reflection. The default composite score
converts each available summary metric to average ranks on ,
reverses ranks for higher-is-better metrics, applies the documented weights,
and renormalizes the weights after omitting unavailable metrics. Lower
composite scores are better.
A list with runs and summary data frames and,
optionally, realized layouts.
edges <- edges.path(5) cmp <- compare.layouts( edges = edges, n = 5, dim = 2, candidates = c("default", "tree"), seeds = 1L ) cmp$summary[, c("candidate", "rounds", "final.rounds")] search.cmp <- compare.layouts( edges = edges, n = 5, dim = 2, search = list( candidate.prefix = "path.search", rounds = c(4L, 6L), final.rounds = c(4L, 6L) ), seeds = 1L ) search.cmp$summary[, c("candidate", "rounds", "final.rounds")]edges <- edges.path(5) cmp <- compare.layouts( edges = edges, n = 5, dim = 2, candidates = c("default", "tree"), seeds = 1L ) cmp$summary[, c("candidate", "rounds", "final.rounds")] search.cmp <- compare.layouts( edges = edges, n = 5, dim = 2, search = list( candidate.prefix = "path.search", rounds = c(4L, 6L), final.rounds = c(4L, 6L) ), seeds = 1L ) search.cmp$summary[, c("candidate", "rounds", "final.rounds")]
Convenience constructors for cubic keep-arrays that can be passed to
recursive.cube.mask.surface.graph() to build cubical porous
benchmark families. These helpers encode three qualitatively different void
patterns: repeated tunnel lattices, interior asymmetric cavities, and
deterministic channel networks.
mask.cube.periodic.tunnels( side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 2 ) mask.cube.asymmetric.cavities( side = 5, cavity.size = 2, pocket.size = max(1L, cavity.size - 1L) ) mask.cube.channel.network(side = 5, channel.width = 1, branch.offset = 2)mask.cube.periodic.tunnels( side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 2 ) mask.cube.asymmetric.cavities( side = 5, cavity.size = 2, pocket.size = max(1L, cavity.size - 1L) ) mask.cube.channel.network(side = 5, channel.width = 1, branch.offset = 2)
side |
Side length of the cubic keep-array. |
tunnel.width |
Width of each removed tunnel band. |
tunnel.period |
Spacing between successive tunnel bands. |
tunnel.offset |
Starting index of the first tunnel band. |
cavity.size |
Side length of the larger interior cavity block. |
pocket.size |
Side length of the smaller secondary cavity block. |
channel.width |
Width of each removed channel in the channel-network family. |
branch.offset |
Interior offset of the extra branch channel in
|
The returned arrays use the same orientation as the recursive cube-mask helpers: the first dimension runs from top to bottom, the second from left to right, and the third from front to back.
A logical cubic keep-array.
cavities <- mask.cube.asymmetric.cavities( side = 5, cavity.size = 1, pocket.size = 1 ) channels <- mask.cube.channel.network( side = 5, channel.width = 1, branch.offset = 2 ) tunnels <- mask.cube.periodic.tunnels( side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 1 )cavities <- mask.cube.asymmetric.cavities( side = 5, cavity.size = 1, pocket.size = 1 ) channels <- mask.cube.channel.network( side = 5, channel.width = 1, branch.offset = 2 ) tunnels <- mask.cube.periodic.tunnels( side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 1 )
Convenience helpers that embed a cylindrical grid graph into
and use the induced Euclidean edge lengths as positive
graph weights. These helpers are intended for benchmark families where the
graph topology is cylindrical but the intended metric comes from a curved or
spatially varying 3D realization.
cylinder.surface.graph( h, w = h, surface = c("barrel", "hourglass", "wavy"), radius = 1, height = 2, amplitude = 0.3, freq.theta = 2, freq.z = 1, twist = 0.25, normalize = c("median", "mean", "none") )cylinder.surface.graph( h, w = h, surface = c("barrel", "hourglass", "wavy"), radius = 1, height = 2, amplitude = 0.3, freq.theta = 2, freq.z = 1, twist = 0.25, normalize = c("median", "mean", "none") )
h |
Number of rows. |
w |
Number of columns. Defaults to |
surface |
Cylinder surface family. One of |
radius |
Positive baseline cylinder radius. |
height |
Positive cylinder height. |
amplitude |
Finite numeric deformation amplitude. The resulting radius profile must stay positive everywhere. |
freq.theta |
Positive angular frequency used only when
|
freq.z |
Positive vertical frequency used only when
|
twist |
Finite angular twist applied linearly with height. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component contains the 3D coordinates of the embedded
cylindrical grid. cylinder.surface.graph() returns a reusable weighted-graph
bundle containing the cylinder edges, induced edge weights, the 3D surface
coordinates, and a 2D unwrapped parameterization.
The coords_surface component is an n x 3 numeric matrix
with columns x, y, and z.
cylinder.surface.graph() returns a list with components:
edges: the undirected cylindrical-grid edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the 2D unwrapped parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "cylinder",
surface: the chosen surface name,
label: a human-readable family label.
cylinder <- cylinder.surface.graph(4, 5, surface = "hourglass")cylinder <- cylinder.surface.graph(4, 5, surface = "hourglass")
edge.kk() is the edge-restricted Kamada–Kawai local repair operator for
the experimental GMDS layout program. Earlier notes called this operator
edge-gKK or edge-isometric GMDS; edge-KK is the preferred name because the
objective is restricted to graph edges rather than all graph-geodesic pairs.
It minimizes weighted edge-length stress
using deterministic gradient descent with Armijo backtracking. The default
density.mix.schedule runs a continuation from density-weighted stiffnesses
toward uniform stiffnesses.
edge.kk( coords = NULL, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2L, init = c("classical_mds", "metric_mds", "weighted_grip", "random"), weighted.grip.args = list(), stiffness.method = c("density", "uniform", "distance_power"), stiffness.transform = c("identity", "sqrt", "log"), density.mix.schedule = c(0, 0.25, 0.5, 0.75, 1), bandwidth = NULL, density.n = 512L, distance.power = 0, stiffness.floor = 0, stiffness.ceiling = Inf, scale.mode = c("profiled", "identity", "fixed_initial", "user"), scale = NULL, max.iter = 50L, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, edge.length.epsilon = 1e-08, distance.floor = 1e-08, recenter = TRUE, return.trace = TRUE, diagnostics = TRUE, seed = 1L, engine = c("cpp", "R") )edge.kk( coords = NULL, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2L, init = c("classical_mds", "metric_mds", "weighted_grip", "random"), weighted.grip.args = list(), stiffness.method = c("density", "uniform", "distance_power"), stiffness.transform = c("identity", "sqrt", "log"), density.mix.schedule = c(0, 0.25, 0.5, 0.75, 1), bandwidth = NULL, density.n = 512L, distance.power = 0, stiffness.floor = 0, stiffness.ceiling = Inf, scale.mode = c("profiled", "identity", "fixed_initial", "user"), scale = NULL, max.iter = 50L, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, edge.length.epsilon = 1e-08, distance.floor = 1e-08, recenter = TRUE, return.trace = TRUE, diagnostics = TRUE, seed = 1L, engine = c("cpp", "R") )
coords |
Optional starting coordinates. If omitted, |
prepared |
Optional object returned by |
edges |
Two-column integer edge matrix used when |
n |
Finite positive integer vertex count. When supplied with a prepared object, it must match the stored graph size. |
adj.list |
Optional adjacency list used when |
weight.list |
Optional edge-weight list parallel to |
edge.weights |
Optional positive edge weights parallel to |
dim |
Target embedding dimension. |
init |
Starting layout used when |
weighted.grip.args |
Named list of additional tuning arguments passed
to |
stiffness.method, stiffness.transform, density.mix.schedule, bandwidth, density.n
|
Parameters passed to |
distance.power, stiffness.floor, stiffness.ceiling
|
Additional stiffness constructor parameters. |
scale.mode |
Scale policy for edge targets. |
scale |
User scale for |
max.iter |
Maximum iterations per continuation stage. |
initial.step, step.shrink, armijo.factor, grad.tol, min.step
|
Line-search controls. |
edge.length.epsilon |
Small stabilizer for fixed-path embedded lengths. |
distance.floor |
Positive floor for relative residuals. |
recenter |
If |
return.trace |
If |
diagnostics |
If |
seed |
Random seed used for |
engine |
Optimizer engine. |
For scalable repair from an existing layout, pass coords or an edge-only
object from prepare.edge.kk(). When raw graph inputs are supplied,
edge.kk() uses edge-only preparation whenever coords are supplied or
init is "weighted_grip" or "random". Use init = "weighted_grip" for a scalable
weighted-GRIP warm start followed by edge-KK polish. If coords is omitted
and either MDS initializer is requested, use an all-pairs prepared object from
prepare.graph.geodesic.mds() or prepare.geodesic.kk() instead.
A "grip_gmds_layout" object with method "edge_kk".
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.edge.kk(cycle_edges, n = 6) fit <- edge.kk( coords = initial, prepared = prepared, max.iter = 1, density.n = 32, engine = "R" )cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.edge.kk(cycle_edges, n = 6) fit <- edge.kk( coords = initial, prepared = prepared, max.iter = 1, density.n = 32, engine = "R" )
edge.length.density.stiffness() constructs stiffnesses for edge-only
geodesic-MDS layouts. It turns positive edge lengths into
spring stiffnesses normalized to mean one. The "density" method emphasizes
edge lengths near the empirical edge-length density mode, and mix provides
a continuation path from that density-weighted signal to uniform stiffness.
edge.length.density.stiffness( edge.weights, method = c("density", "uniform", "distance_power"), mix = 0, bandwidth = NULL, density.n = 512L, transform = c("identity", "sqrt", "log"), distance.power = 0, stiffness.floor = 0, stiffness.ceiling = Inf )edge.length.density.stiffness( edge.weights, method = c("density", "uniform", "distance_power"), mix = 0, bandwidth = NULL, density.n = 512L, transform = c("identity", "sqrt", "log"), distance.power = 0, stiffness.floor = 0, stiffness.ceiling = Inf )
edge.weights |
Positive numeric edge lengths. |
method |
Stiffness rule. |
mix |
Continuation parameter in |
bandwidth |
Optional bandwidth passed to |
density.n |
Number of evaluation points for |
transform |
Optional transformation of the raw density/power signal before mixing and normalization. |
distance.power |
Exponent for |
stiffness.floor, stiffness.ceiling
|
Optional clipping bounds applied before the final mean-one normalization. |
A list with stiffness, raw signal diagnostics, estimated mode, and
clipping/normalization metadata.
stiffness <- edge.length.density.stiffness( c(0.8, 0.9, 1, 1.1, 1.2, 1.3), density.n = 32 )stiffness <- edge.length.density.stiffness( c(0.8, 0.9, 1, 1.1, 1.2, 1.3), density.n = 32 )
edge.repulsive.stage() performs one gradient-descent stage
for the objective evaluated by edge.repulsive.state(). It uses Armijo
backtracking, optionally recenters coordinates after each proposal, and
returns the final coordinates plus a per-iteration trace.
edge.repulsive.stage( coords, edges, edge.lengths, edge.weights = NULL, lambda = 0, edge.family = c("quadratic", "upper_barrier"), eps.plus = 0.35, beta = 0, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, max.iter = 80L, initial.step = 0.02, step.shrink = 0.5, armijo = 1e-04, min.step = 1e-08, grad.tol = 1e-07, recenter = TRUE, distance.eps = 1e-10, return.frames = FALSE, engine = c("cpp", "R") )edge.repulsive.stage( coords, edges, edge.lengths, edge.weights = NULL, lambda = 0, edge.family = c("quadratic", "upper_barrier"), eps.plus = 0.35, beta = 0, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, max.iter = 80L, initial.step = 0.02, step.shrink = 0.5, armijo = 1e-04, min.step = 1e-08, grad.tol = 1e-07, recenter = TRUE, distance.eps = 1e-10, return.frames = FALSE, engine = c("cpp", "R") )
coords |
Numeric |
edges |
Integer or numeric matrix with two columns containing 1-based graph edge endpoints. |
edge.lengths |
Numeric vector of target edge lengths, parallel to
|
edge.weights |
Optional non-negative edge weights. Defaults to one. |
lambda |
Repulsion strength. |
edge.family |
Edge potential family, either |
eps.plus |
Upper-barrier slack parameter. |
beta |
Upper-barrier strength. When |
pair.index |
Optional two-column matrix of 1-based vertex pairs for the
repulsion term. If |
pair.weights |
Optional pair weights, parallel to |
repulsion.family |
Repulsion potential family, either |
repulsion.delta |
Small positive softening parameter for pair distances. |
repulsion.power |
Power used by the |
max.iter |
Maximum number of gradient-descent iterations. |
initial.step |
Initial gradient step size. |
step.shrink |
Multiplicative shrink factor used by backtracking. |
armijo |
Armijo sufficient-decrease coefficient. |
min.step |
Minimum allowable step before the stage stops. |
grad.tol |
Gradient-norm stopping tolerance. |
recenter |
Logical; whether to recenter coordinates after each proposal. |
distance.eps |
Small positive distance floor used in derivatives. |
return.frames |
Logical; whether to return accepted coordinate frames. Frame 0 is the starting coordinate matrix and later frames are accepted updates. |
engine |
Backend engine. |
A list with coords, final state, a data-frame trace, and,
when requested, a list of coordinate frames.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) fit <- edge.repulsive.stage( initial, cycle_edges, rep(1, nrow(cycle_edges)), lambda = 0.1, max.iter = 1, engine = "R" )cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) fit <- edge.repulsive.stage( initial, cycle_edges, rep(1, nrow(cycle_edges)), lambda = 0.1, max.iter = 1, engine = "R" )
edge.repulsive.state() evaluates an experimental GMDS objective that
combines an edge-isometric term with a configurable repulsion term. The edge
term penalizes deviation of embedded edge lengths from graph edge lengths.
The repulsion term can be evaluated on all vertex pairs or on a selected pair
set.
edge.repulsive.state( coords, edges, edge.lengths, edge.weights = NULL, edge.family = c("quadratic", "upper_barrier"), eps.plus = 0.35, beta = 0, lambda = 0, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, distance.eps = 1e-10, engine = c("cpp", "R") )edge.repulsive.state( coords, edges, edge.lengths, edge.weights = NULL, edge.family = c("quadratic", "upper_barrier"), eps.plus = 0.35, beta = 0, lambda = 0, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, distance.eps = 1e-10, engine = c("cpp", "R") )
coords |
Numeric |
edges |
Integer or numeric matrix with two columns containing 1-based graph edge endpoints. |
edge.lengths |
Numeric vector of target edge lengths, parallel to
|
edge.weights |
Optional non-negative edge weights. Defaults to one. |
edge.family |
Edge potential family, either |
eps.plus |
Upper-barrier slack parameter. |
beta |
Upper-barrier strength. When |
lambda |
Repulsion strength. |
pair.index |
Optional two-column matrix of 1-based vertex pairs for the
repulsion term. If |
pair.weights |
Optional pair weights, parallel to |
repulsion.family |
Repulsion potential family, either |
repulsion.delta |
Small positive softening parameter for pair distances. |
repulsion.power |
Power used by the |
distance.eps |
Small positive distance floor used in derivatives. |
engine |
Backend engine. |
The default engine = "cpp" uses the compiled backend. engine = "R" keeps
a reference implementation available for diagnostics and regression tests.
A list containing total energy, edge and repulsion energies, gradient, gradient norm, feasibility flag, embedded edge lengths, relative edge lengths, edge residuals, and number of upper-barrier wall violations.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) state <- edge.repulsive.state( coords, cycle_edges, rep(1, nrow(cycle_edges)), lambda = 0.1, engine = "R" )cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) state <- edge.repulsive.state( coords, cycle_edges, rep(1, nrow(cycle_edges)), lambda = 0.1, engine = "R" )
Reports a lower bound for dense distance storage, not peak memory or runtime. This arithmetic-only helper does not construct a graph or allocate its cache.
estimate.preparation( n, n.edges = NA_integer_, pair.mode = c("all_pairs", "landmark_sparse", "distance_matrix_only", "edge_only"), local.nbrs = 20L, landmark.count = 8L )estimate.preparation( n, n.edges = NA_integer_, pair.mode = c("all_pairs", "landmark_sparse", "distance_matrix_only", "edge_only"), local.nbrs = 20L, landmark.count = 8L )
n |
Number of vertices. |
n.edges |
Number of undirected edges, or NA if unknown. |
pair.mode |
Preparation mode: full paths, landmark paths, distances only, or edges only. |
local.nbrs, landmark.count
|
Counts used by landmark preparation. |
One dense double matrix needs 8 * n^2 bytes. Full and landmark
preparations currently compute dense distances; landmark mode reduces
retained pairs, not that matrix. Trees, routes, copies, R object overhead,
and solver workspace require additional memory and are not estimated.
Edge-only preparation has no dense distance matrix, but still stores the
graph. Use prepare.edge.kk() when only edge constraints are needed, or
ordinary grip() when a full geodesic cache is unnecessary.
Dense preparation warns before its searches/allocations when this bound
exceeds getOption("grip.preparation.warn.bytes", 512 * 1024^2).
Set that option to another positive byte count, or Inf to acknowledge and
disable the advisory warning. It is not a hard memory limit. Small calls are
quiet. Native refinement checks for cancellation between rounds or optimizer
evaluations; worker threads finish an evaluation before interruption is
raised on the main thread. Cancellation does not return a partial fit.
A one-row data frame containing graph counts, pair mode, a pair-count upper bound, and the dense-distance storage lower bound in bytes and GiB.
prepare.graph.geodesic.mds(), prepare.landmark.geodesic.kk()
estimate.preparation(10000, n.edges = 20000) estimate.preparation(10000, n.edges = 20000, pair.mode = "edge_only")estimate.preparation(10000, n.edges = 20000) estimate.preparation(10000, n.edges = 20000, pair.mode = "edge_only")
geodesic.kk() applies a deterministic gradient-descent
polish under the full all-pairs geodesic Kamada–Kawai objective.
geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, max.iter = 16L, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, recenter = TRUE, return.trace = FALSE, scale.mode = c("fixed_initial", "profiled", "user"), scale.L0 = NULL )geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, max.iter = 16L, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, recenter = TRUE, return.trace = FALSE, scale.mode = c("fixed_initial", "profiled", "user"), scale.L0 = NULL )
coords |
Numeric coordinate matrix with 2 or 3 columns. |
prepared |
Optional object returned by
|
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
max.iter |
Maximum number of gradient-descent iterations. |
stiffness |
Global stiffness constant \(K\). |
distance.floor |
Small positive floor used in
|
edge.length.epsilon |
Small positive stabilizer added inside each embedded edge length. |
initial.step |
Initial line-search step size. |
step.shrink |
Multiplicative shrink factor in |
armijo.factor |
Non-negative Armijo decrease constant. |
grad.tol |
Non-negative stopping tolerance on the gradient norm. |
min.step |
Positive minimum accepted line-search step before giving up. |
recenter |
If |
return.trace |
If |
scale.mode |
One of |
scale.L0 |
Optional user-supplied fixed scale, required when
|
The optimizer supports three scale policies. With
scale.mode = "fixed_initial" the target scale is fit once from the
starting layout and then held fixed during optimization, matching the
landmark geodesic KK behavior. With scale.mode = "profiled" the scale is
re-fit analytically at each evaluation. With scale.mode = "user", a
fixed user-supplied scale.L0 is used throughout.
A list with coords, trace, frames,
prepared, and score.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.geodesic.kk(cycle_edges, n = 6) fit <- geodesic.kk(initial, prepared = prepared, max.iter = 1)cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.geodesic.kk(cycle_edges, n = 6) fit <- geodesic.kk(initial, prepared = prepared, max.iter = 1)
geometry.diagnostics() augments the graph-aware quality measures
in score.layout() with target-aware geometric diagnostics.
The function aligns coords to target.coords using an orthogonal
Procrustes fit, then reports global symmetry, local angle preservation,
edge-axis concentration, and, for Sierpinski carpet layouts, boundary,
corridor, and hole-center diagnostics.
geometry.diagnostics( coords, target.coords, edges, family = NULL, sample.size.symmetry = 512L, sample.size.wedges = 4000L, rng.seed = 1L )geometry.diagnostics( coords, target.coords, edges, family = NULL, sample.size.symmetry = 512L, sample.size.wedges = 4000L, rng.seed = 1L )
coords |
Numeric layout matrix with 2 or 3 columns. |
target.coords |
Canonical target coordinates with the same shape as
|
edges |
Two-column integer edge matrix. |
family |
Optional graph-family label. Use |
sample.size.symmetry |
Number of vertices sampled when evaluating global symmetry. |
sample.size.wedges |
Number of wedges sampled when evaluating local angle deviation. |
rng.seed |
Integer seed used for the symmetry and wedge sampling. |
Metrics are reported so that larger global.symmetry.score and
edge.axis.concentration are better, while smaller
procrustes.rmse, local.angle.deviation,
boundary.waviness, corridor.waviness,
hole.center.error, central.hole.skew,
central.hole.aspect.error, and central.hole.center.error are
better.
A one-row data frame of geometric diagnostics.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] target <- cbind(cos(theta), sin(theta)) diagnostics <- geometry.diagnostics( target + 0.01, target, cycle_edges, sample.size.symmetry = 10, sample.size.wedges = 10 )cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] target <- cbind(cos(theta), sin(theta)) diagnostics <- geometry.diagnostics( target + 0.01, target, cycle_edges, sample.size.symmetry = 10, sample.size.wedges = 10 )
This compatibility entry point is equivalent to
grip(..., metric = "hop"). It keeps the old
global-repulsion name available while using the same quality-first
multiscale GRIP engine and adaptive final.rounds schedule as the
primary layout API.
globalrep.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, tinit.factor = 6, seed = 6, disconnected = c("components", "error") )globalrep.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, tinit.factor = 6, seed = 6, disconnected = c("components", "error") )
edges |
Two-column integer matrix of edges (1-based vertex ids).
Supply either |
n |
Number of vertices, a finite positive integer. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Optional parallel list of positive edge lengths for
|
edge.weights |
Optional positive edge lengths for |
dim |
Layout dimension (2 or 3). Default is 3. |
placement |
Initial placement strategy. "circle" is only used for 2D. |
preset |
Optional tuning preset. |
rounds |
Initial rounds for refinement. |
final.rounds |
Final rounds for refinement. |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of graph-distance neighbors retained for local refinement at each filtration level. |
r |
Main local temperature adaptation rate in |
s |
Non-negative boost factor applied when successive displacements have a consistent direction. |
repulsion.factor |
Non-negative multiplier applied to GRIP's finest-level repulsive force scale. |
coarse.repulsion.factor |
Non-negative multiplier applied to the extra
coarse-level active-set repulsion term. |
coarse.repulsion.sample |
Positive integer sample size used to approximate active-set-wide repulsion on larger coarse levels. |
coarse.repulsion.exact.below |
Positive integer threshold. When the active set size is at most this value, the coarse repulsion is computed exactly against all currently active vertices instead of being sampled. |
final.anchor.factor |
Non-negative multiplier for an anchor term that
pulls the final FR stage back toward the pre-final full-graph layout.
|
final.move.scale.after.first |
Scalar in |
final.mode |
Final full-graph refinement mode. |
insertion.anchor.count |
Positive integer number of anchor vertices used
during multiscale insertion on non-initial MISF refinement levels. This is
the closest current implementation to a global |
insertion.anchor.scope |
Anchor-eligibility rule used during multiscale
insertion. |
insertion.anchor.strategy |
Anchor-selection rule used during
multiscale insertion. |
level0.insertion.mode |
Level-0 insertion placement override used only
when the finest filtration level is first populated. |
level0.anchor.count |
Positive integer number of already placed anchors
to collect for level-0 insertion experiments. By default this inherits
|
level0.local.kk.steps |
Non-negative integer number of tiny local KK micro-polish steps applied immediately after each level-0 insertion. The legacy behavior uses 3. |
lgkk.polish.rounds |
Non-negative integer number of experimental
landmark-geodesic KK polish iterations applied after the main GRIP solve.
|
lgkk.multiscale.rounds |
Non-negative integer number of compiled
landmark-geodesic KK refinement rounds applied inside the multiscale solver
after each eligible MISF level completes its standard GRIP rounds.
This legacy shared budget is used as a fallback when any of the more
specific per-stage budgets below are left |
lgkk.rounds.coarse |
Optional non-negative integer number of compiled
LGKK rounds applied on coarse MISF levels with |
lgkk.rounds.pre.final |
Optional non-negative integer number of compiled
LGKK rounds applied on the last coarse level just before the full graph is
opened ( |
lgkk.rounds.final |
Optional non-negative integer number of compiled
LGKK rounds applied after the full graph level completes its standard GRIP
rounds ( |
lgkk.local.nbrs |
Number of nearest graph-metric neighbors retained per vertex in the LGKK sparse local set when either LGKK stage is enabled. |
lgkk.landmark.count |
Number of farthest-point landmarks retained per vertex in the LGKK sparse long-range set when either LGKK stage is enabled. |
lgkk.multiscale.scope |
Scope for the compiled multiscale LGKK stage.
|
lgkk.active.limit |
Positive integer upper bound on the active-set size for compiled multiscale LGKK cache construction. Levels larger than this skip the multiscale LGKK stage. |
tinit.factor |
Initial temperature factor. |
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
disconnected |
How to handle disconnected graphs:
|
A numeric matrix with n rows and dim columns.
edges <- edges.mesh(4, 4) coords <- globalrep.grip(edges, n = max(edges), dim = 2, rounds = 8, final.rounds = 8, num.init = 6, num.nbrs = 8, coarse.repulsion.factor = 0.2, coarse.repulsion.sample = 8, coarse.repulsion.exact.below = 32, seed = 1) round(coords, 3)edges <- edges.mesh(4, 4) coords <- globalrep.grip(edges, n = max(edges), dim = 2, rounds = 8, final.rounds = 8, num.init = 6, num.nbrs = 8, coarse.repulsion.factor = 0.2, coarse.repulsion.sample = 8, coarse.repulsion.exact.below = 32, seed = 1) round(coords, 3)
globalrep.weighted.grip() is the compatibility backend equivalent to
grip(..., metric = "edge_length"). It runs the edge-length
multiscale core, which uses edge lengths in the filtration, local
neighborhoods, insertion, refinement forces, and optional in-core
multiscale LGKK refinement.
globalrep.weighted.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, metric.neighbor.cap = NULL, length.normalization = c("median", "mean", "none"), tinit.factor = 6, seed = 6, disconnected = c("components", "error") )globalrep.weighted.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, metric.neighbor.cap = NULL, length.normalization = c("median", "mean", "none"), tinit.factor = 6, seed = 6, disconnected = c("components", "error") )
edges |
Two-column integer matrix of edges (1-based vertex ids).
Supply either |
n |
Number of vertices, a finite positive integer. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Parallel list of positive edge lengths for
|
edge.weights |
Positive edge lengths for |
dim |
Layout dimension (2 or 3). Default is 3. |
placement |
Initial placement strategy. "circle" is only used for 2D. |
preset |
Optional weighted tuning preset. |
rounds |
Initial rounds for refinement. |
final.rounds |
Final rounds for refinement. |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of graph-distance neighbors retained for local refinement at each filtration level. |
r |
Main local temperature adaptation rate in |
s |
Non-negative boost factor applied when successive displacements have a consistent direction. |
repulsion.factor |
Non-negative multiplier applied to GRIP's finest-level repulsive force scale. |
coarse.repulsion.factor |
Non-negative multiplier applied to the extra
coarse-level active-set repulsion term. |
coarse.repulsion.sample |
Positive integer sample size used to approximate active-set-wide repulsion on larger coarse levels. |
coarse.repulsion.exact.below |
Positive integer threshold. When the active set size is at most this value, the coarse repulsion is computed exactly against all currently active vertices instead of being sampled. |
final.anchor.factor |
Non-negative multiplier for an anchor term that
pulls the final FR stage back toward the pre-final full-graph layout.
|
final.move.scale.after.first |
Scalar in |
final.mode |
Final full-graph refinement mode. |
insertion.anchor.count |
Positive integer number of anchor vertices used
during multiscale insertion on non-initial MISF refinement levels. This is
the closest current implementation to a global |
insertion.anchor.scope |
Anchor-eligibility rule used during multiscale
insertion. |
insertion.anchor.strategy |
Anchor-selection rule used during
multiscale insertion. |
level0.insertion.mode |
Level-0 insertion placement override used only
when the finest filtration level is first populated. |
level0.anchor.count |
Positive integer number of already placed anchors
to collect for level-0 insertion experiments. By default this inherits
|
level0.local.kk.steps |
Non-negative integer number of tiny local KK micro-polish steps applied immediately after each level-0 insertion. The legacy behavior uses 3. |
lgkk.polish.rounds |
Non-negative integer number of experimental
landmark-geodesic KK polish iterations applied after the main GRIP solve.
|
lgkk.multiscale.rounds |
Non-negative integer number of compiled
landmark-geodesic KK refinement rounds applied inside the multiscale solver
after each eligible MISF level completes its standard GRIP rounds.
This legacy shared budget is used as a fallback when any of the more
specific per-stage budgets below are left |
lgkk.rounds.coarse |
Optional non-negative integer number of compiled
LGKK rounds applied on coarse MISF levels with |
lgkk.rounds.pre.final |
Optional non-negative integer number of compiled
LGKK rounds applied on the last coarse level just before the full graph is
opened ( |
lgkk.rounds.final |
Optional non-negative integer number of compiled
LGKK rounds applied after the full graph level completes its standard GRIP
rounds ( |
lgkk.local.nbrs |
Number of nearest graph-metric neighbors retained per vertex in the LGKK sparse local set when either LGKK stage is enabled. |
lgkk.landmark.count |
Number of farthest-point landmarks retained per vertex in the LGKK sparse long-range set when either LGKK stage is enabled. |
lgkk.multiscale.scope |
Scope for the compiled multiscale LGKK stage.
|
lgkk.active.limit |
Positive integer upper bound on the active-set size for compiled multiscale LGKK cache construction. Levels larger than this skip the multiscale LGKK stage. |
metric.neighbor.cap |
Optional cap on the number of settled Dijkstra
vertices used when building weighted neighborhood caches for inserted
vertices. |
length.normalization |
Global edge-length normalization:
|
tinit.factor |
Initial temperature factor. |
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
disconnected |
How to handle disconnected graphs:
|
A numeric matrix with n rows and dim columns.
cycle_edges <- edges.cycle(6) cycle_lengths <- seq(0.8, 1.3, length.out = nrow(cycle_edges)) layout <- globalrep.weighted.grip( edges = cycle_edges, n = 6, edge.weights = cycle_lengths, dim = 2, rounds = 1, final.rounds = 1, num.init = 3, num.nbrs = 2, seed = 1 )cycle_edges <- edges.cycle(6) cycle_lengths <- seq(0.8, 1.3, length.out = nrow(cycle_edges)) layout <- globalrep.weighted.grip( edges = cycle_edges, n = 6, edge.weights = cycle_lengths, dim = 2, rounds = 1, final.rounds = 1, num.init = 3, num.nbrs = 2, seed = 1 )
Convenience helpers that build small undirected graph families as two-column
integer edge matrices suitable for grip(). These
helpers are meant for examples, experiments, and reproducible tests.
edges.path(n) edges.cycle(n) edges.mesh(h, w = h, connectivity = c("orthogonal", "diagonal")) edges.cylinder(h, w = h) edges.torus(h, w = h) edges.cube(side = 2) edges.kary.tree(k = 2, depth = 2) edges.sierpinski.triangle(level = 2) edges.sierpinski.tetrahedron(level = 2) edges.sierpinski.carpet(level = 2)edges.path(n) edges.cycle(n) edges.mesh(h, w = h, connectivity = c("orthogonal", "diagonal")) edges.cylinder(h, w = h) edges.torus(h, w = h) edges.cube(side = 2) edges.kary.tree(k = 2, depth = 2) edges.sierpinski.triangle(level = 2) edges.sierpinski.tetrahedron(level = 2) edges.sierpinski.carpet(level = 2)
n |
Number of vertices. |
h |
Number of rows. |
w |
Number of columns. Defaults to |
connectivity |
Mesh neighborhood rule. |
side |
Number of lattice points along each cube edge. |
k |
Branching factor. |
depth |
Number of levels below the root. |
level |
Recursion depth for the Sierpinski graph families. Must be at least 1. |
The exported generators cover primitive paths, cycles, regular meshes,
cylinders, tori, cubes, trees, and the standard Sierpinski families.
Specialized weighted benchmark families are exposed through complete
*.surface.graph() and *.solid.graph() bundles instead of separate
edge-list and embedding functions. edges.sierpinski.triangle()
builds the 2-simplex family,
edges.sierpinski.tetrahedron() builds the 3-simplex family,
and edges.sierpinski.carpet() builds a 2D cell-adjacency
carpet graph.
A two-column integer matrix of undirected edges. Vertex labels are consecutive integers starting at 1.
edges.path(): Path graph on n vertices.
edges.cycle(): Cycle graph on n vertices.
edges.mesh(): Rectangular grid graph with h rows and w
columns.
edges.cylinder(): Cylindrical grid graph with h rows and wrapped
width w.
edges.torus(): Toroidal grid graph with wrapped height and
width.
edges.cube(): Cube surface graph on the boundary of a
side x side x side lattice.
edges.kary.tree(): Full k-ary tree of depth depth.
edges.sierpinski.triangle(): Two-dimensional Sierpinski triangle graph at
recursion depth level.
edges.sierpinski.tetrahedron(): Three-dimensional tetrahedral Sierpinski graph
at recursion depth level.
edges.sierpinski.carpet(): Two-dimensional Sierpinski carpet graph whose
vertices are occupied cells and whose edges connect orthogonally adjacent
cells.
cube_edges <- edges.cube(3) cycle_edges <- edges.cycle(6) cylinder_edges <- edges.cylinder(3, 4) tree_edges <- edges.kary.tree(k = 2, depth = 2) mesh_edges <- edges.mesh(3, 4) carpet_edges <- edges.sierpinski.carpet(level = 1) tetrahedron_edges <- edges.sierpinski.tetrahedron(level = 1) torus_edges <- edges.torus(3, 4) edges <- edges.path(6) coords <- grip(edges, n = 6, dim = 2, seed = 1) plot.layout(coords, edges, main = "Path graph", pch = 16, cex = 0.8) edges <- edges.sierpinski.triangle(2) n <- max(edges) coords <- grip(edges, n = n, dim = 2, placement = "circle", seed = 1) plot.layout(coords, edges, main = "Sierpinski triangle", pch = 16, cex = 0.7)cube_edges <- edges.cube(3) cycle_edges <- edges.cycle(6) cylinder_edges <- edges.cylinder(3, 4) tree_edges <- edges.kary.tree(k = 2, depth = 2) mesh_edges <- edges.mesh(3, 4) carpet_edges <- edges.sierpinski.carpet(level = 1) tetrahedron_edges <- edges.sierpinski.tetrahedron(level = 1) torus_edges <- edges.torus(3, 4) edges <- edges.path(6) coords <- grip(edges, n = 6, dim = 2, seed = 1) plot.layout(coords, edges, main = "Path graph", pch = 16, cex = 0.8) edges <- edges.sierpinski.triangle(2) n <- max(edges) coords <- grip(edges, n = n, dim = 2, placement = "circle", seed = 1) plot.layout(coords, edges, main = "Sierpinski triangle", pch = 16, cex = 0.7)
graph.riemannian.star.structure() builds the local star-pair table used by
kernel Gram-gKK. For each center vertex u, it considers unordered neighbor
pairs (v, v') in the graph star and stores the target edge lengths, target
cosine angle, and kernel weight
In the first implementation, target angles are estimated from the ambient
coordinates X. The optimizer is intentionally agnostic to where those
cosines came from, so later graph constructors can attach a different
Riemannian source without changing the layout backend.
graph.riemannian.star.structure( graph = NULL, X, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, angle.power = 4, reliability = c("length.balance", "none"), min.angle.weight = 0, star.quantile = 0 )graph.riemannian.star.structure( graph = NULL, X, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, angle.power = 4, reliability = c("length.balance", "none"), min.angle.weight = 0, star.quantile = 0 )
graph |
Optional graph/prepared object containing |
X |
Numeric matrix used to estimate local target angles. |
prepared |
Optional prepared GMDS object. Used when |
edges, n, edge.weights
|
Optional edge representation used when |
adj.list, weight.list
|
Optional adjacency-list representation. |
angle.power |
Non-negative exponent |
reliability |
Reliability weighting rule. |
min.angle.weight |
Pairs with final angle weight at or below this value are omitted from the returned table. |
star.quantile |
Optional quantile in |
A list of class "grip_riemannian_star" with the star-pair table and
construction metadata.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) star <- graph.riemannian.star.structure(X = coords, prepared = prepared)cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) star <- graph.riemannian.star.structure(X = coords, prepared = prepared)
This is the primary layout API. It uses the quality-first multiscale GRIP
engine with extra coarse-level global repulsion to reduce foldovers while
preserving the usual GRIP refinement structure. With preset = NULL,
the default profile is tuned for higher-quality layouts and automatically
tapers final.rounds on larger graphs.
grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, tinit.factor = 6, seed = 6, disconnected = c("components", "error"), metric = c("hop", "edge_length"), metric.neighbor.cap = NULL, length.normalization = c("median", "mean", "none") )grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, tinit.factor = 6, seed = 6, disconnected = c("components", "error"), metric = c("hop", "edge_length"), metric.neighbor.cap = NULL, length.normalization = c("median", "mean", "none") )
edges |
Two-column integer matrix of edges (1-based vertex ids).
Supply either |
n |
Number of vertices, a finite positive integer. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Parallel list of edge lengths for |
edge.weights |
Vector of edge lengths for |
dim |
Layout dimension (2 or 3). Default is 3. |
placement |
Initial placement strategy. "circle" is only used for 2D. |
preset |
Optional tuning preset. |
rounds |
Initial rounds for refinement. |
final.rounds |
Final rounds for refinement. |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of graph-distance neighbors retained for local refinement at each filtration level. |
r |
Main local temperature adaptation rate in |
s |
Non-negative boost factor applied when successive displacements have a consistent direction. |
repulsion.factor |
Non-negative multiplier applied to GRIP's finest-level repulsive force scale. |
coarse.repulsion.factor |
Non-negative multiplier applied to the extra
coarse-level active-set repulsion term. |
coarse.repulsion.sample |
Positive integer sample size used to approximate active-set-wide repulsion on larger coarse levels. |
coarse.repulsion.exact.below |
Positive integer threshold. When the active set size is at most this value, the coarse repulsion is computed exactly against all currently active vertices instead of being sampled. |
final.anchor.factor |
Non-negative multiplier for an anchor term that
pulls the final FR stage back toward the pre-final full-graph layout.
|
final.move.scale.after.first |
Scalar in |
final.mode |
Final full-graph refinement mode. |
insertion.anchor.count |
Positive integer number of anchor vertices used
during multiscale insertion on non-initial MISF refinement levels. This is
the closest current implementation to a global |
insertion.anchor.scope |
Anchor-eligibility rule used during multiscale
insertion. |
insertion.anchor.strategy |
Anchor-selection rule used during
multiscale insertion. |
level0.insertion.mode |
Level-0 insertion placement override used only
when the finest filtration level is first populated. |
level0.anchor.count |
Positive integer number of already placed anchors
to collect for level-0 insertion experiments. By default this inherits
|
level0.local.kk.steps |
Non-negative integer number of tiny local KK micro-polish steps applied immediately after each level-0 insertion. The legacy behavior uses 3. |
lgkk.polish.rounds |
Non-negative integer number of experimental
landmark-geodesic KK polish iterations applied after the main GRIP solve.
|
lgkk.multiscale.rounds |
Non-negative integer number of compiled
landmark-geodesic KK refinement rounds applied inside the multiscale solver
after each eligible MISF level completes its standard GRIP rounds.
This legacy shared budget is used as a fallback when any of the more
specific per-stage budgets below are left |
lgkk.rounds.coarse |
Optional non-negative integer number of compiled
LGKK rounds applied on coarse MISF levels with |
lgkk.rounds.pre.final |
Optional non-negative integer number of compiled
LGKK rounds applied on the last coarse level just before the full graph is
opened ( |
lgkk.rounds.final |
Optional non-negative integer number of compiled
LGKK rounds applied after the full graph level completes its standard GRIP
rounds ( |
lgkk.local.nbrs |
Number of nearest graph-metric neighbors retained per vertex in the LGKK sparse local set when either LGKK stage is enabled. |
lgkk.landmark.count |
Number of farthest-point landmarks retained per vertex in the LGKK sparse long-range set when either LGKK stage is enabled. |
lgkk.multiscale.scope |
Scope for the compiled multiscale LGKK stage.
|
lgkk.active.limit |
Positive integer upper bound on the active-set size for compiled multiscale LGKK cache construction. Levels larger than this skip the multiscale LGKK stage. |
tinit.factor |
Initial temperature factor. |
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
disconnected |
How to handle disconnected graphs:
|
metric |
Graph metric used by the multiscale GRIP engine.
|
metric.neighbor.cap |
Weighted-metric search limit used only when
|
length.normalization |
Global normalization applied only when
|
Edge-length semantics
The arguments edge.weights and weight.list are historically
named but represent positive edge lengths or traversal costs, not
connection strengths, capacities, or similarities. A larger value requests
a longer geometric edge. If the available values are strengths for which a
larger value means a closer connection, convert them to positive lengths
before calling grip(), for example with a scientifically appropriate
reciprocal or other monotone decreasing transformation.
With metric = "hop", the standard GRIP hierarchy, insertion anchors,
and retained local neighborhoods use combinatorial shortest-path distance:
every traversed edge contributes one hop. When edge lengths are supplied,
they are nevertheless used as the desired lengths of adjacent vertex pairs
in the attractive force calculation. Thus this mode is useful when topology
should determine the multiscale organization but adjacent edges should have
unequal target lengths. No global length normalization is performed in this
mode. If no lengths are supplied, every edge has desired length one. Optional
LGKK stages use the supplied edge lengths for their geodesic distances even
though the standard GRIP stages remain hop based.
With metric = "edge_length", positive edge lengths are required. The
same lengths determine desired adjacent-edge lengths and the shortest-path
metric used for the MISF hierarchy, insertion anchors, retained graph
neighborhoods, and LGKK stages. Dijkstra-style weighted shortest paths are
used instead of hop-count breadth-first searches. By default, all lengths
are divided by their median before layout; this preserves relative geometry
while placing the numerical scale near the solver's unit scale. Use
length.normalization = "mean" for mean scaling or "none" when
the absolute supplied scale is intentional. Multiplying all input lengths
by the same positive constant therefore leaves the default normalized solve
unchanged.
For edges input, provide one value per row through
edge.weights. For adj.list input, provide a parallel
weight.list: weight.list[[i]][j] is the length of the edge from
vertex i to adj.list[[i]][j]. For an undirected graph, the
adjacency and length entries should be symmetric.
A numeric matrix with n rows and dim columns.
Start with vignette("function-guide", package = "grip")
to choose a layout, diagnostic, or reference comparison. List installed
guides with vignette(package = "grip").
Gajer, P. and Kobourov, S.G. (2002). GRIP: Graph dRawing with Intelligent Placement. Journal of Graph Algorithms and Applications, 6(3), 203–224. doi:10.7155/jgaa.00052.
Gajer, P., Goodrich, M.T. and Kobourov, S.G. (2004). A multi-dimensional approach to force-directed layouts of large graphs. Computational Geometry, 29(1), 3–18. doi:10.1016/j.comgeo.2004.03.014.
edges <- edges.mesh(4, 4) coords <- grip(edges, n = max(edges), dim = 2, coarse.repulsion.factor = 0.2, coarse.repulsion.sample = 8, coarse.repulsion.exact.below = 32, seed = 1) round(coords, 3) # Use edge lengths throughout the multiscale graph metric. path <- cbind(1:5, 2:6) lengths <- c(1, 1, 2, 1, 1) weighted.coords <- grip( path, n = 6, edge.weights = lengths, metric = "edge_length", dim = 2, rounds = 4, final.rounds = 4, num.init = 3, seed = 1 )edges <- edges.mesh(4, 4) coords <- grip(edges, n = max(edges), dim = 2, coarse.repulsion.factor = 0.2, coarse.repulsion.sample = 8, coarse.repulsion.exact.below = 32, seed = 1) round(coords, 3) # Use edge lengths throughout the multiscale graph metric. path <- cbind(1:5, 2:6) lengths <- c(1, 1, 2, 1, 1) weighted.coords <- grip( path, n = 6, edge.weights = lengths, metric = "edge_length", dim = 2, rounds = 4, final.rounds = 4, num.init = 3, seed = 1 )
Version 0.2.0 removes the long-form compatibility aliases that were deprecated in the 0.1 series and narrows the exported graph-family API. The canonical replacements are listed below.
grip.layout() -> grip()
grip.layout.globalrep() -> globalrep.grip()
grip.layout.globalrep.weighted() -> globalrep.weighted.grip()
grip.layout.legacy() -> legacy.grip()
grip.layout.trace() -> trace.grip()
grip.layout.trace.legacy() -> trace.legacy.grip()
grip.layout.trace.weighted() -> trace.grip(metric = "edge_length")
grip.layout.weighted() -> grip(metric = "edge_length")
grip.layout.weighted.nd() -> weighted.grip.nd()
grip.plot() -> plot.layout()
grip.project.3d() -> project.3d()
grip.metric.mds.layout() -> classical.mds() (classical scaling)
grip.optimize.kernel.gram.gkk.layout() -> kernel.gram.gkk()
grip.score.gmds.layout() -> score.gmds()
grip.gmds.layout.result() -> gmds.result() (now internal)
grip.edge.length.density.stiffness() ->
edge.length.density.stiffness()
grip.prepare.landmark.geodesic.kk() ->
prepare.landmark.geodesic.kk()
grip.prepare.geodesic.kk() -> prepare.geodesic.kk()
grip.prepare.graph.geodesic.mds() ->
prepare.graph.geodesic.mds()
grip.prepare.misf.geodesic.kk() -> prepare.misf.geodesic.kk()
grip.prepare.edge.kk() -> prepare.edge.kk()
grip.score.landmark.geodesic.kk() -> score.landmark.geodesic.kk()
grip.score.geodesic.kk() -> score.geodesic.kk()
grip.score.misf.geodesic.kk() -> score.misf.geodesic.kk()
grip.optimize.landmark.geodesic.kk() -> landmark.geodesic.kk()
grip.optimize.geodesic.kk() -> geodesic.kk()
grip.optimize.misf.geodesic.kk() -> misf.geodesic.kk()
grip.optimize.edge.kk.layout() -> edge.kk()
grip.optimize.edge.gkk.layout() -> edge.kk()
grip.optimize.edge.isometric.layout() -> edge.kk()
grip.optimize.edge.repulsive.stage() -> edge.repulsive.stage()
grip.optimize.repulsive.stage() -> repulsive.stage()
grip.edge.repulsive.state() -> edge.repulsive.state()
grip.repulsive.state() -> repulsive.state()
grip.build.misf.weighted() -> build.weighted.misf()
grip.build.misf() -> build.misf()
grip.geometry.diagnostics() -> geometry.diagnostics()
grip.params.from.summary() -> params.from.summary()
grip.score.layout() -> score.layout()
grip.compare.layouts() -> compare.layouts()
Complete *.surface.graph() and *.solid.graph() constructors remain
public and return reusable bundles. Use the bundle's edges,
coords.surface, and coords.param components instead of the former
specialized edge-list, standalone embedding, and parameter-coordinate
exports. Primitive generators such as edges.path(), edges.cycle(),
edges.mesh(), and edges.cube() remain public.
In grip through version 0.2.0, metric.mds() used stats::cmdscale().
From version 0.2.0.9000, that algorithm is named classical.mds(), and
metric.mds() minimizes raw distance stress, using native SGD by default.
This is an intentional behavioral change rather than a deprecated alias.
Replace metric.mds(...) with classical.mds(...), and explicit
init = "metric_mds" with init = "classical_mds". Both edge.kk()
and kernel.gram.gkk() default to classical initialization, preserving
their previous default algorithm without requiring smacof.
add and eig are classical-scaling arguments and are accepted only by
classical.mds(). Existing saved coordinates, figure labels, and cache
fields named metric_mds from older versions remain classical results.
Renaming a call does not require recomputing those fits.
Use metric.mds(...) or edge.kk(init = "metric_mds", ...) to use the
default native SGD backend. For control over multiple starts and budgets,
call metric.mds() first and pass coords = fit$coords to edge.kk().
Check metadata$starts, metadata$termination, and the independently
calculated stress diagnostics. Both backends are local optimizers; an
iteration limit or a finite result does not certify an optimum.
Install the optional smacof package and explicitly request
metric.mds(backend = "smacof", ...). The eps tolerance belongs to that
backend and must not be supplied to SGD. To retain a SMACOF initializer in
a refinement workflow, compute it explicitly and pass its coordinates to
edge.kk() or kernel.gram.gkk(). No automatic backend fallback is made.
metric.mds(backend = "sgd", max.iter = 30, ...) explicitly selects the
default backend with a short trial budget, without requiring smacof.
SGD uses the same uniform pair weights and shortest-path targets. Its controls
remain provisional calibration choices, and max.iter counts complete pair
passes. Schedule completion is reported as iteration_limit, not convergence.
Inspect per-start records and metadata$sgd checkpoint histories. Selecting
init = "metric_mds" in refinement methods follows the default SGD backend;
their default init = "classical_mds" is unchanged. A different optimizer
cannot repair inaccurate graph distances.
Raw stress is measured against the original graph-distance units after restoring scale from the backend. Target-normalized raw stress and scale-profiled Stress-1 have the same optimal shapes when scale is free and pair weights match, but literal Stress-1 at the returned raw-stress scale is a different diagnostic value. Record the algorithm, objective, backend/package versions, graph identity, scale policy, and start settings in new result manifests. Recompute downstream refinement when changing its initializer, and use new cache identities rather than replacing historical classical results in place.
gripui Shiny applicationBuild the gripui Shiny application
gripui.app(project)gripui.app(project)
project |
A |
A shiny.appobj.
graph <- list(adj_list = list(2L, c(1L, 3L), 2L)) layouts <- data.frame( candidate = "toy.layout", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = graph, layouts = layouts, title = "Toy project") app <- gripui.app(project) inherits(app, "shiny.appobj")graph <- list(adj_list = list(2L, c(1L, 3L), 2L)) layouts <- data.frame( candidate = "toy.layout", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = graph, layouts = layouts, title = "Toy project") app <- gripui.app(project) inherits(app, "shiny.appobj")
Build the graph-family geometry explorer Shiny application
gripui.family.app( catalog = gripui.graph.family.catalog(), title = "Graph Family Geometry Explorer", subtitle = "Interactive geometry browser for synthetic benchmark families." )gripui.family.app( catalog = gripui.graph.family.catalog(), title = "Graph Family Geometry Explorer", subtitle = "Interactive geometry browser for synthetic benchmark families." )
catalog |
Family catalog, usually |
title |
Application title. |
subtitle |
Optional subtitle shown in the sidebar. |
A shiny.appobj.
app <- gripui.family.app() inherits(app, "shiny.appobj")app <- gripui.family.app() inherits(app, "shiny.appobj")
The catalog is a registry used by gripui.family.app() to populate its
family selector, presets, parameter controls, builder calls, and source
references.
gripui.graph.family.catalog()gripui.graph.family.catalog()
A named list of family descriptors.
catalog <- gripui.graph.family.catalog() names(catalog) catalog$mesh$function_namecatalog <- gripui.graph.family.catalog() names(catalog) catalog$mesh$function_name
gripui project objectCreate a normalized gripui project object
gripui.project( graph = NULL, layouts, title = NULL, subtitle = NULL, notes = NULL )gripui.project( graph = NULL, layouts, title = NULL, subtitle = NULL, notes = NULL )
graph |
Optional graph object used by layout viewers. This may be a
single list containing fields such as |
layouts |
Data frame with one row per realized layout. |
title |
Optional project title. |
subtitle |
Optional subtitle. |
notes |
Optional notes string. |
An object of class gripui_project.
graph <- list(adj_list = list(2L, c(1L, 3L), c(2L, 4L), 3L)) layouts <- data.frame( candidate = "path.default", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = graph, layouts = layouts, title = "Path graph") project$meta$titlegraph <- list(adj_list = list(2L, c(1L, 3L), c(2L, 4L), 3L)) layouts <- data.frame( candidate = "path.default", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = graph, layouts = layouts, title = "Path graph") project$meta$title
compare.layouts() output into a gripui_project
Convert compare.layouts() output into a gripui_project
gripui.project.from.compare( compare.obj, graph = NULL, vertex.data = NULL, graph.info = NULL, title = NULL )gripui.project.from.compare( compare.obj, graph = NULL, vertex.data = NULL, graph.info = NULL, title = NULL )
compare.obj |
Result of |
graph |
Optional graph object, named graph list, or path to a graph RDS.
Defaults to |
vertex.data |
Optional vertex metadata added to |
graph.info |
Optional graph-level metadata added to |
title |
Optional project title. |
A gripui_project.
edges <- edges.path(5) cmp <- compare.layouts( edges = edges, n = 5, candidates = "default", seeds = 1L, return.layouts = TRUE ) graph <- list( adj_list = list(2L, c(1L, 3L), c(2L, 4L), c(3L, 5L), 4L) ) project <- gripui.project.from.compare(cmp, graph = graph, title = "Path compare") nrow(project$layouts)edges <- edges.path(5) cmp <- compare.layouts( edges = edges, n = 5, candidates = "default", seeds = 1L, return.layouts = TRUE ) graph <- list( adj_list = list(2L, c(1L, 3L), c(2L, 4L), c(3L, 5L), 4L) ) project <- gripui.project.from.compare(cmp, graph = graph, title = "Path compare") nrow(project$layouts)
gripui_project from a directory of saved artifactsCreate a gripui_project from a directory of saved artifacts
gripui.project.from.dir(root, graph = NULL, title = NULL, subtitle = NULL)gripui.project.from.dir(root, graph = NULL, title = NULL, subtitle = NULL)
root |
Directory containing either a normalized |
graph |
Optional graph object, named graph list, or path to a graph RDS. |
title |
Optional project title. |
subtitle |
Optional subtitle. |
A gripui_project.
root <- tempfile("gripui-bundle-") dir.create(root) on.exit(unlink(root, recursive = TRUE, force = TRUE), add = TRUE) dir.create(file.path(root, "catalog"), recursive = TRUE, showWarnings = FALSE) dir.create(file.path(root, "graph"), recursive = TRUE, showWarnings = FALSE) dir.create(file.path(root, "artifacts", "layouts"), recursive = TRUE, showWarnings = FALSE) graph <- list(adj_list = list(2L, c(1L, 3L), 2L)) saveRDS(graph, file.path(root, "graph", "graph.rds")) coords.path <- file.path(root, "artifacts", "layouts", "toy_embedding.tsv") utils::write.table( data.frame( vertex_id = c("v1", "v2", "v3"), x = c(1, 2, 3), y = c(0, 0, 0), stringsAsFactors = FALSE ), file = coords.path, sep = "\t", quote = TRUE, row.names = FALSE, col.names = TRUE ) utils::write.table( data.frame( candidate = "toy.layout", stage = "bundle", seed = 1L, status = "ok", coords_path = file.path("artifacts", "layouts", "toy_embedding.tsv"), stringsAsFactors = FALSE ), file = file.path(root, "catalog", "layout_catalog.tsv"), sep = "\t", quote = TRUE, row.names = FALSE, col.names = TRUE ) project <- gripui.project.from.dir(root, title = "My project") project$layouts$availabilityroot <- tempfile("gripui-bundle-") dir.create(root) on.exit(unlink(root, recursive = TRUE, force = TRUE), add = TRUE) dir.create(file.path(root, "catalog"), recursive = TRUE, showWarnings = FALSE) dir.create(file.path(root, "graph"), recursive = TRUE, showWarnings = FALSE) dir.create(file.path(root, "artifacts", "layouts"), recursive = TRUE, showWarnings = FALSE) graph <- list(adj_list = list(2L, c(1L, 3L), 2L)) saveRDS(graph, file.path(root, "graph", "graph.rds")) coords.path <- file.path(root, "artifacts", "layouts", "toy_embedding.tsv") utils::write.table( data.frame( vertex_id = c("v1", "v2", "v3"), x = c(1, 2, 3), y = c(0, 0, 0), stringsAsFactors = FALSE ), file = coords.path, sep = "\t", quote = TRUE, row.names = FALSE, col.names = TRUE ) utils::write.table( data.frame( candidate = "toy.layout", stage = "bundle", seed = 1L, status = "ok", coords_path = file.path("artifacts", "layouts", "toy_embedding.tsv"), stringsAsFactors = FALSE ), file = file.path(root, "catalog", "layout_catalog.tsv"), sep = "\t", quote = TRUE, row.names = FALSE, col.names = TRUE ) project <- gripui.project.from.dir(root, title = "My project") project$layouts$availability
gripui_project
Validate a gripui_project
gripui.validate.project(project)gripui.validate.project(project)
project |
Object to validate. |
Invisibly returns TRUE when validation succeeds.
layouts <- data.frame( candidate = "test.layout", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = NULL, layouts = layouts, title = "Validation example") gripui.validate.project(project)layouts <- data.frame( candidate = "test.layout", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = NULL, layouts = layouts, title = "Validation example") gripui.validate.project(project)
A symmetric k-nearest-neighbor graph constructed from samples from the Ravel-led University of Maryland Baltimore Human Microbiome Project (UMB-HMP) longitudinal vaginal cohort, generated by Illumina 16S rRNA amplicon sequencing. Rows without an explicit HMP project label, rows from the related U01 cohort, and legacy 454 runs are excluded before preprocessing.
hmp.gchmp.gc
A named list with components:
Adjacency list with 1-based integer neighbor indices.
Parallel list of Euclidean edge lengths in the ten-component PCA representation.
Data frame with one row per HMP sample and columns for sample identifier, HMP project, sequencing platform and phase, CST and subCST annotations, and retained-read diagnostics.
Named list recording the cohort filter, representation,
graph constructor, selected k, and graph dimensions.
Taxonomic count features detected in at least one percent of the retained
HMP samples are converted to relative abundance and represented by ten
principal components. A symmetric k = 3 nearest-neighbor graph is built in
that representation, and the largest connected component is retained.
Derived from Illumina 16S rRNA amplicon profiles from the Ravel-led
UMB-HMP longitudinal vaginal cohort. Exact graph edges, sample metadata,
feature screening results, and provenance are distributed under
inst/extdata/hmp_gc/.
data(hmp.gc) length(hmp.gc$adj_list) hmp.gc$graph_info[c("assay", "graph_constructor", "selected_k")]data(hmp.gc) length(hmp.gc$adj_list) hmp.gc$graph_info[c("assay", "graph_constructor", "selected_k")]
A bundled coarsened graph derived from the giant connected component of the
HMP+U01 16S amplicon iKNN graph used in the HMP/U01 layout-selection study.
The upstream graph came from the >=1% relative-abundance plus PCA branch
with k = 3, after restricting to the biologically meaningful major
component. The graph was then greedily coarsened in two rounds from 6474
vertices to 1828 supernodes.
hmp.u01.gc.coarsehmp.u01.gc.coarse
A named list with components:
Adjacency list of length 1828, with 1-based integer
neighbor indices.
Parallel list of positive edge weights.
Data frame with one row per coarse vertex and columns
vertex_id, size, cst, subcst, dcst.depth1.absorb,
dcst.depth1.rare, dcst.depth2.absorb, dcst.depth2.rare, ph, and
log10_reads.
Named list summarizing provenance and graph-level
metadata, including the original and coarsened vertex counts, selected
k, edge count, and coarsening rounds.
The object is intended for examples and vignettes on real-world 3D layout comparison. It is small enough to ship with the package while preserving the arm-like graph structure that motivated the tuned preset analysis.
Derived from the publicly available HMP+U01 16S amplicon analysis
workflow used in the chm_paper project. Raw bundled artifacts and a
provenance note are available under
inst/extdata/hmp_u01_gc_coarse/.
data(hmp.u01.gc.coarse) length(hmp.u01.gc.coarse$adj_list) head(hmp.u01.gc.coarse$vertex_data[, c("vertex_id", "size", "cst", "subcst")])data(hmp.u01.gc.coarse) length(hmp.u01.gc.coarse$adj_list) head(hmp.u01.gc.coarse$vertex_data[, c("vertex_id", "size", "cst", "subcst")])
Convenience helpers that build an annulus from deterministically irregular
concentric rings with varying sample counts, stitch adjacent rings into a
locally triangulated graph, and then optionally lift the resulting irregular
planar parameterization into . This provides a non-lattice
annulus family with boundary and nonuniform local valence.
irregular.annulus.surface.graph( rings = 6, outer.count = 28, outer.radius = 1, inner.radius = 0.45, count.irregularity = 0.2, radial.irregularity = 0.35, phase.twist = 0.35, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )irregular.annulus.surface.graph( rings = 6, outer.count = 28, outer.radius = 1, inner.radius = 0.45, count.irregularity = 0.2, radial.irregularity = 0.35, phase.twist = 0.35, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )
rings |
Number of concentric sample rings, including the inner and outer boundary cycles. |
outer.count |
Approximate number of vertices on the outer boundary. |
outer.radius |
Positive outer annulus radius. |
inner.radius |
Positive inner annulus radius. |
count.irregularity |
Irregularity level for the per-ring sample counts.
Must lie in |
radial.irregularity |
Irregularity level for within-ring radial
perturbations. Must lie in |
phase.twist |
Finite angular phase offset used to desynchronize neighboring rings. |
surface |
Geometry family used for the 3D lift. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the first planar coordinate. Used
only when |
freq.v |
Positive ripple frequency in the second planar coordinate. Used
only when |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
irregular.annulus.surface.graph() returns a list with components:
edges: the irregular annulus edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the irregular planar annulus coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.annulus",
surface: the chosen surface name,
rings: number of concentric rings,
ring_sizes: sample counts on each ring,
label: a human-readable family label.
annulus <- irregular.annulus.surface.graph(rings = 3, outer.count = 12)annulus <- irregular.annulus.surface.graph(rings = 3, outer.count = 12)
Convenience helpers that build a layered simplicial ball by taking a subdivided triangulated polyhedron, normalizing its vertices to directions on the sphere, placing those directions on nested radial layers, and connecting adjacent layers by a deterministic prism-to-tetrahedra edge pattern. The center vertex is included explicitly, so the resulting graph is genuinely volumetric rather than just a closed surface.
irregular.ball.solid.graph( base = c("tetrahedron", "octahedron", "icosahedron"), level = 1, layers = 3, outer.radius = 1, radial.irregularity = 0.25, layer.twist = 0.35, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq.theta = 2, freq.phi = 2, twist = 0.6, normalize = c("median", "mean", "none") )irregular.ball.solid.graph( base = c("tetrahedron", "octahedron", "icosahedron"), level = 1, layers = 3, outer.radius = 1, radial.irregularity = 0.25, layer.twist = 0.35, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq.theta = 2, freq.phi = 2, twist = 0.6, normalize = c("median", "mean", "none") )
base |
Base polyhedron. One of |
level |
Surface subdivision depth used for each radial layer. |
layers |
Number of non-center radial layers. |
outer.radius |
Positive outer radius of the ball. |
radial.irregularity |
Irregularity level for the radial layer spacing.
Must lie in |
layer.twist |
Finite z-axis twist applied smoothly across radial layers. |
surface |
Solid geometry family. One of |
amplitude |
Finite deformation amplitude. |
freq.theta |
Positive azimuthal modulation frequency used only when
|
freq.phi |
Positive polar modulation frequency used only when
|
twist |
Finite twist strength used only when
|
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
irregular.ball.solid.graph() returns a list with components:
edges: the irregular ball edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the canonical 3D ball coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.ball",
surface: the chosen solid geometry family,
base: the chosen base polyhedron,
level: the surface subdivision depth,
layers: number of non-center radial layers,
radii: the radial layer values,
label: a human-readable family label.
ball <- irregular.ball.solid.graph( base = "tetrahedron", level = 0, layers = 2 )ball <- irregular.ball.solid.graph( base = "tetrahedron", level = 0, layers = 2 )
Convenience helpers that build a closed genus-2 surface from a
deterministically irregular slice family whose cyclic cross-sections follow a
1 -> 3 -> 1 loop transition between two poles. This gives a non-lattice,
point-sampled double-torus graph together with either the canonical 3D
embedding or simple bulged, twisted, and wavy deformations of that geometry.
irregular.double.torus.surface.graph( slices = 11, tube.count = 14, branch.length = 0.85, branch.offset = 0.72, tube.radius = 0.28, transition.width = 0.42, count.irregularity = 0.2, axial.irregularity = 0.3, phase.twist = 0.35, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.25, freq.x = 2, freq.theta = 2, twist = 0.6, normalize = c("median", "mean", "none") )irregular.double.torus.surface.graph( slices = 11, tube.count = 14, branch.length = 0.85, branch.offset = 0.72, tube.radius = 0.28, transition.width = 0.42, count.irregularity = 0.2, axial.irregularity = 0.3, phase.twist = 0.35, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.25, freq.x = 2, freq.theta = 2, twist = 0.6, normalize = c("median", "mean", "none") )
slices |
Number of non-pole slices through the double torus. |
tube.count |
Approximate number of vertices around each tube-like loop. |
branch.length |
Half-length of the three-loop central region. |
branch.offset |
Offset of the outer loop centers from the central loop. |
tube.radius |
Baseline radius of each tube-like loop. |
transition.width |
Width of the left and right transition regions between the single-loop and three-loop slices. |
count.irregularity |
Irregularity level for the per-component sample
counts. Must lie in |
axial.irregularity |
Irregularity level for the slice spacing. Must lie
in |
phase.twist |
Finite phase offset used to desynchronize neighboring cyclic slices. |
surface |
Double-torus geometry family. One of |
amplitude |
Finite deformation amplitude. |
freq.x |
Positive modulation frequency along the axial direction. Used
only when |
freq.theta |
Positive angular modulation frequency around the local
tube direction. Used only when |
twist |
Finite twist strength used only when
|
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
irregular.double.torus.surface.graph() returns a list with
components:
edges: the irregular double-torus edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the canonical 3D double-torus coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.double.torus",
surface: the chosen surface name,
slices: number of non-pole slices,
slice_sizes: vertex counts in each slice,
slice_components: number of cyclic components in each slice,
label: a human-readable family label.
double_torus <- irregular.double.torus.surface.graph( slices = 7, tube.count = 8 )double_torus <- irregular.double.torus.surface.graph( slices = 7, tube.count = 8 )
Convenience helpers that build a pair-of-pants domain from deterministically
irregular horizontal slices, sample each surviving slice interval with
varying point counts, and stitch adjacent slices into a locally triangulated
surface-with-boundary graph. The resulting irregular planar parameterization
can then be lifted into using the same planar surface
families as the triangulated annulus and irregular annulus helpers.
irregular.pair.of.pants.surface.graph( slices = 11, outer.count = 28, outer.radius = 1.1, hole.radius = 0.24, hole.offset = 0.38, hole.height = 0.18, count.irregularity = 0.2, vertical.irregularity = 0.35, phase.twist = 0.35, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )irregular.pair.of.pants.surface.graph( slices = 11, outer.count = 28, outer.radius = 1.1, hole.radius = 0.24, hole.offset = 0.38, hole.height = 0.18, count.irregularity = 0.2, vertical.irregularity = 0.35, phase.twist = 0.35, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )
slices |
Number of horizontal sample slices through the pair-of-pants domain. |
outer.count |
Approximate number of vertices across the widest slices. |
outer.radius |
Positive outer boundary radius. |
hole.radius |
Positive radius of each interior hole. |
hole.offset |
Positive horizontal offset of the two hole centers. |
hole.height |
Shared vertical coordinate of the two hole centers. |
count.irregularity |
Irregularity level for the per-slice sample counts.
Must lie in |
vertical.irregularity |
Irregularity level for slice spacing. Must lie
in |
phase.twist |
Finite phase offset used to desynchronize neighboring slice samples. |
surface |
Geometry family used for the 3D lift. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the first planar coordinate. Used
only when |
freq.v |
Positive ripple frequency in the second planar coordinate. Used
only when |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
irregular.pair.of.pants.surface.graph() returns a list with
components:
edges: the irregular pair-of-pants edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the irregular planar pair-of-pants coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.pair.of.pants",
surface: the chosen surface name,
slices: number of horizontal sample slices,
slice_sizes: vertex counts in each slice,
slice_components: number of connected slice intervals in each
slice,
label: a human-readable family label.
pair_of_pants <- irregular.pair.of.pants.surface.graph( slices = 5, outer.count = 12 )pair_of_pants <- irregular.pair.of.pants.surface.graph( slices = 5, outer.count = 12 )
Convenience helpers that keep ordinary rectangular-mesh adjacency but replace the regular parameter grid by a deterministic irregular rectangle. The resulting family stays simply connected and rectangular in topology while breaking the strongest row/column symmetries of the lattice.
irregular.rectangle.surface.graph( h, w = h, surface = c("flat", "saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, row.irregularity = 0.2, col.irregularity = 0.2, row.phase = 0.35, col.phase = 0.65, interior.warp = 0.08, shear = 0, min.step.ratio = 0.3, connectivity = c("orthogonal", "diagonal"), normalize = c("median", "mean", "none") )irregular.rectangle.surface.graph( h, w = h, surface = c("flat", "saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, row.irregularity = 0.2, col.irregularity = 0.2, row.phase = 0.35, col.phase = 0.65, interior.warp = 0.08, shear = 0, min.step.ratio = 0.3, connectivity = c("orthogonal", "diagonal"), normalize = c("median", "mean", "none") )
h |
Number of rows. |
w |
Number of columns. Defaults to |
surface |
Surface family used for the lift. One of |
amplitude |
Finite numeric amplitude controlling the non-flat displacement. |
freq.u |
Positive ripple frequency in the horizontal parameter
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical parameter direction.
Used only when |
x.scale |
Positive horizontal scaling of the parameter domain. |
y.scale |
Positive vertical scaling of the parameter domain. |
row.irregularity |
Irregularity level for the row spacing. Must lie in
|
col.irregularity |
Irregularity level for the column spacing. Must lie
in |
row.phase |
Finite phase shift for the deterministic row-spacing perturbation. |
col.phase |
Finite phase shift for the deterministic column-spacing perturbation. |
interior.warp |
Non-negative interior warp strength. Must lie in
|
shear |
Finite affine shear applied after the boundary-vanishing warp. Larger values can force a validation error if the mesh cells invert. |
min.step.ratio |
Positive lower bound for the perturbed row and column
interval lengths, expressed relative to the unperturbed interval scale.
Must lie in |
connectivity |
Mesh neighborhood rule passed to |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.param component contains the irregular planar parameter
coordinates.
The coords.surface component lifts those coordinates into
.
irregular.rectangle.surface.graph() returns a reusable weighted-graph
bundle with the induced Euclidean edge lengths.
The coords_param component is an n x 2 numeric
matrix with columns u and v.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
irregular.rectangle.surface.graph() returns a list with components:
edges: the undirected rectangular-mesh edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the irregular 2D parameter coordinates,
coords_regular_param: the underlying regular 2D parameter
coordinates used to define the boundary-vanishing warp,
row_breaks: per-row parameter coordinates in row order,
col_breaks: per-column parameter coordinates in column order,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.rectangle",
surface: the chosen surface name,
connectivity: the chosen mesh connectivity rule,
label: a human-readable family label.
rectangle <- irregular.rectangle.surface.graph(4, 5, surface = "ripple")rectangle <- irregular.rectangle.surface.graph(4, 5, surface = "ripple")
Convenience helpers that build a layered simplicial shell by placing the
vertices of a subdivided triangulated polyhedron on nested inner-to-outer
radial layers and connecting adjacent layers by the same deterministic
prism-to-tetrahedra edge pattern used for irregular.ball.solid.*().
The result is a genuinely volumetric shell graph with a hollow interior.
irregular.shell.solid.graph( base = c("tetrahedron", "octahedron", "icosahedron"), level = 1, layers = 3, inner.radius = 0.45, outer.radius = 1, radial.irregularity = 0.25, layer.twist = 0.35, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq.theta = 2, freq.phi = 2, twist = 0.6, normalize = c("median", "mean", "none") )irregular.shell.solid.graph( base = c("tetrahedron", "octahedron", "icosahedron"), level = 1, layers = 3, inner.radius = 0.45, outer.radius = 1, radial.irregularity = 0.25, layer.twist = 0.35, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq.theta = 2, freq.phi = 2, twist = 0.6, normalize = c("median", "mean", "none") )
base |
Base polyhedron. One of |
level |
Surface subdivision depth used for each radial layer. |
layers |
Number of non-center radial layers. |
inner.radius |
Positive inner radius of the shell. |
outer.radius |
Positive outer radius of the ball. |
radial.irregularity |
Irregularity level for the radial layer spacing.
Must lie in |
layer.twist |
Finite z-axis twist applied smoothly across radial layers. |
surface |
Solid geometry family. One of |
amplitude |
Finite deformation amplitude. |
freq.theta |
Positive azimuthal modulation frequency used only when
|
freq.phi |
Positive polar modulation frequency used only when
|
twist |
Finite twist strength used only when
|
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
irregular.shell.solid.graph() returns the same components as
irregular.ball.solid.graph(), with family set to
"irregular.shell".
shell <- irregular.shell.solid.graph( base = "tetrahedron", level = 0, layers = 2 )shell <- irregular.shell.solid.graph( base = "tetrahedron", level = 0, layers = 2 )
Convenience helpers that build a sphere from deterministically irregular
latitude bands with varying sample counts, stitch adjacent bands into a
locally triangulated graph, and then realize that graph in
using either a standard sphere, an ellipsoid, or a wavy radial modulation.
irregular.sphere.surface.graph( bands = 6, equator.count = 28, count.irregularity = 0.2, lat.irregularity = 0.35, phase.twist = 0.35, surface = c("standard", "ellipsoid", "wavy"), radius = 1, amplitude = 0.2, freq.theta = 3, freq.lat = 2, twist = 0.25, normalize = c("median", "mean", "none") )irregular.sphere.surface.graph( bands = 6, equator.count = 28, count.irregularity = 0.2, lat.irregularity = 0.35, phase.twist = 0.35, surface = c("standard", "ellipsoid", "wavy"), radius = 1, amplitude = 0.2, freq.theta = 3, freq.lat = 2, twist = 0.25, normalize = c("median", "mean", "none") )
bands |
Number of non-pole latitude bands. |
equator.count |
Approximate number of vertices near the equator. |
count.irregularity |
Irregularity level for per-band sample counts.
Must lie in |
lat.irregularity |
Irregularity level for latitude-band spacing. Must
lie in |
phase.twist |
Finite angular phase offset used to desynchronize neighboring latitude bands. |
surface |
Sphere geometry family. One of |
radius |
Positive baseline radius. |
amplitude |
Finite deformation amplitude. For |
freq.theta |
Positive longitudinal frequency used only when
|
freq.lat |
Positive latitudinal frequency used only when
|
twist |
Finite longitude twist applied smoothly by latitude. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
irregular.sphere.surface.graph() returns a list with components:
edges: the irregular sphere edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the irregular angular parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.sphere",
surface: the chosen surface name,
bands: number of non-pole latitude bands,
band_sizes: sample counts in each latitude band,
label: a human-readable family label.
sphere <- irregular.sphere.surface.graph(bands = 3, equator.count = 12)sphere <- irregular.sphere.surface.graph(bands = 3, equator.count = 12)
Convenience helpers that build a torus from deterministically irregular
major-cycle rings with varying sample counts, stitch adjacent rings into a
locally triangulated toroidal graph, and then realize that graph in
using either a standard, pinched, or wavy tube geometry.
irregular.torus.surface.graph( major.rings = 8, tube.count = 16, count.irregularity = 0.2, major.irregularity = 0.25, phase.twist = 0.35, surface = c("standard", "pinched", "wavy"), major.radius = 2, minor.radius = 0.75, amplitude = 0.2, freq.major = 2, freq.minor = 1, twist = 0.25, normalize = c("median", "mean", "none") )irregular.torus.surface.graph( major.rings = 8, tube.count = 16, count.irregularity = 0.2, major.irregularity = 0.25, phase.twist = 0.35, surface = c("standard", "pinched", "wavy"), major.radius = 2, minor.radius = 0.75, amplitude = 0.2, freq.major = 2, freq.minor = 1, twist = 0.25, normalize = c("median", "mean", "none") )
major.rings |
Number of cyclic major rings around the torus. |
tube.count |
Approximate number of vertices around each minor cycle. |
count.irregularity |
Irregularity level for the per-ring sample counts.
Must lie in |
major.irregularity |
Irregularity level for the major-angle ring
spacing. Must lie in |
phase.twist |
Finite phase offset used to desynchronize neighboring minor cycles. |
surface |
Torus geometry family. One of |
major.radius |
Positive distance from the torus center to the center of the tube. |
minor.radius |
Positive baseline radius of the torus tube. |
amplitude |
Finite deformation amplitude. |
freq.major |
Positive angular frequency around the major cycle, used by
|
freq.minor |
Positive angular frequency around the minor cycle, used by
|
twist |
Finite phase twist applied periodically to the minor angle as a function of the major angle. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
irregular.torus.surface.graph() returns a list with components:
edges: the irregular torus edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the irregular angular parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "irregular.torus",
surface: the chosen surface name,
major_rings: number of major-cycle rings,
ring_sizes: sample counts around each ring,
label: a human-readable family label.
torus <- irregular.torus.surface.graph(major.rings = 4, tube.count = 8)torus <- irregular.torus.surface.graph(major.rings = 4, tube.count = 8)
Convenience helpers that keep the exact edges.kary.tree()
topology but assign edge lengths directly from combinatorial tree metadata
rather than from an ambient Euclidean embedding. Each edge weight is
constructed as
so the user can control tapering with depth separately from child-slot asymmetry.
kary.tree.weighted.graph( k = 2, depth = 2, base.length = 1, depth.rule = c("geometric", "constant", "custom"), depth.decay = 0.85, depth.factors = NULL, branch.rule = c("linear", "uniform", "custom"), branch.spread = 0.3, branch.factors = NULL, normalize = c("median", "mean", "none") )kary.tree.weighted.graph( k = 2, depth = 2, base.length = 1, depth.rule = c("geometric", "constant", "custom"), depth.decay = 0.85, depth.factors = NULL, branch.rule = c("linear", "uniform", "custom"), branch.spread = 0.3, branch.factors = NULL, normalize = c("median", "mean", "none") )
k |
Branching factor. Must be at least |
depth |
Number of levels below the root. May be |
base.length |
Positive global edge-length multiplier before normalization. |
depth.rule |
Rule used to build the per-depth multipliers. One of
|
depth.decay |
Positive decay factor used when
|
depth.factors |
Positive custom depth multipliers. Used only when
|
branch.rule |
Rule used to build the per-child-slot multipliers. One of
|
branch.spread |
Non-negative spread used when
|
branch.factors |
Positive custom branch multipliers. Used only when
|
normalize |
Normalization applied to the raw intrinsic edge lengths.
One of |
The returned object is intended as an intrinsic weighted-tree benchmark
family. It exposes the same edge matrix as edges.kary.tree() together
with edge weights, vertex depths, parent indices, and an edge table that
records the depth and branch slot associated with each tree edge.
A list with components:
edges: the k-ary tree edges,
n: number of vertices,
edge_weights: normalized positive intrinsic edge lengths,
weight_scale: normalization constant applied to the raw edge
lengths,
vertex_depth: depth of each vertex, with the root at depth
0,
parent: parent vertex index for each vertex, with the root
parent recorded as 0,
edge_table: data frame containing parent,
child, parent_depth, child_depth,
branch_index, raw_weight, and normalized
edge_weight,
depth_factors: the applied per-depth multipliers,
branch_factors: the applied per-child-slot multipliers,
family: always "kary.tree.weighted",
k: the branching factor,
depth: the requested tree depth,
label: a human-readable family label.
tree <- kary.tree.weighted.graph(k = 2, depth = 2)tree <- kary.tree.weighted.graph(k = 2, depth = 2)
kernel.gram.gkk() extends edge-only gKK with a local
Riemannian star penalty. The off-diagonal Gram term preserves target inner
products between pairs of incident edge directions:
The star weights are built by graph.riemannian.star.structure(), usually
with an antipodal kernel controlled by angle.power.
kernel.gram.gkk( coords = NULL, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, X = NULL, star = NULL, dim = 2L, init = c("classical_mds", "metric_mds", "random"), angle.power = 4, reliability = c("length.balance", "none"), min.angle.weight = 0, star.quantile = 0, lambda.edge = 1, lambda.gram = 1, stiffness.method = c("density", "uniform", "distance_power"), stiffness.transform = c("identity", "sqrt", "log"), density.mix = 1, bandwidth = NULL, density.n = 512L, distance.power = 0, stiffness.floor = 0, stiffness.ceiling = Inf, scale.mode = c("profiled", "identity", "user"), scale = NULL, max.iter = 50L, initial.step = 0.1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, edge.length.epsilon = 1e-08, distance.floor = 1e-08, recenter = TRUE, return.trace = TRUE, diagnostics = TRUE, seed = 1L, engine = c("cpp", "R") )kernel.gram.gkk( coords = NULL, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, X = NULL, star = NULL, dim = 2L, init = c("classical_mds", "metric_mds", "random"), angle.power = 4, reliability = c("length.balance", "none"), min.angle.weight = 0, star.quantile = 0, lambda.edge = 1, lambda.gram = 1, stiffness.method = c("density", "uniform", "distance_power"), stiffness.transform = c("identity", "sqrt", "log"), density.mix = 1, bandwidth = NULL, density.n = 512L, distance.power = 0, stiffness.floor = 0, stiffness.ceiling = Inf, scale.mode = c("profiled", "identity", "user"), scale = NULL, max.iter = 50L, initial.step = 0.1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, edge.length.epsilon = 1e-08, distance.floor = 1e-08, recenter = TRUE, return.trace = TRUE, diagnostics = TRUE, seed = 1L, engine = c("cpp", "R") )
coords |
Optional starting coordinates. If omitted, |
prepared |
Optional object returned by |
edges |
Two-column integer edge matrix used when |
n |
Finite positive integer vertex count. When supplied with a prepared object, it must match the stored graph size. |
adj.list |
Optional adjacency list used when |
weight.list |
Optional edge-weight list parallel to |
edge.weights |
Optional positive edge weights parallel to |
X |
Optional ambient/source coordinates used to build |
star |
Optional object from |
dim |
Target embedding dimension. |
init |
Starting layout used when |
angle.power, reliability, min.angle.weight
|
Passed to
|
star.quantile |
Optional quantile filter passed to
|
lambda.edge, lambda.gram
|
Non-negative weights for the diagonal edge-length and off-diagonal Gram penalties. |
stiffness.method, stiffness.transform, density.mix, bandwidth, density.n
|
Parameters passed to |
distance.power, stiffness.floor, stiffness.ceiling
|
Additional stiffness constructor parameters. |
scale.mode |
Scale policy for edge targets. |
scale |
User scale for |
max.iter |
Maximum iterations per continuation stage. |
initial.step, step.shrink, armijo.factor, grad.tol, min.step
|
Line-search controls. |
edge.length.epsilon |
Small stabilizer for fixed-path embedded lengths. |
distance.floor |
Positive floor for relative residuals. |
recenter |
If |
return.trace |
If |
diagnostics |
If |
seed |
Random seed used only for |
engine |
Optimizer engine. |
A "grip_gmds_layout" object with method "kernel_gram_gkk".
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) fit <- kernel.gram.gkk( coords = initial, prepared = prepared, X = initial, max.iter = 1, density.n = 32, engine = "R" )cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) fit <- kernel.gram.gkk( coords = initial, prepared = prepared, X = initial, max.iter = 1, density.n = 32, engine = "R" )
landmark.geodesic.kk() applies a deterministic
warm-started gradient-descent polish under the sparse landmark geodesic KK
energy. It starts from an existing layout and refines it, rather than
replacing the full multiscale GRIP refinement pipeline.
landmark.geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, local.nbrs = 20L, landmark.count = 8L, max.iter = 16L, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, recenter = TRUE, return.trace = FALSE )landmark.geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, local.nbrs = 20L, landmark.count = 8L, max.iter = 16L, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, recenter = TRUE, return.trace = FALSE )
coords |
Numeric coordinate matrix with 2 or 3 columns. |
prepared |
Optional object returned by
|
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
local.nbrs |
Number of nearest graph-metric neighbors retained per
vertex when |
landmark.count |
Number of farthest-point landmarks retained per vertex
when |
max.iter |
Maximum number of gradient-descent iterations. |
stiffness |
Global stiffness constant \(K\). |
distance.floor |
Small positive floor used in
|
edge.length.epsilon |
Small positive stabilizer added inside each embedded edge length. |
initial.step |
Initial line-search step size. |
step.shrink |
Multiplicative shrink factor in |
armijo.factor |
Non-negative Armijo decrease constant. |
grad.tol |
Non-negative stopping tolerance on the gradient norm. |
min.step |
Positive minimum accepted line-search step before giving up. |
recenter |
If |
return.trace |
If |
The implementation fits the LGKK target scale L0 once from the
starting layout and then optimizes against those fixed target path lengths.
That keeps the gradient simple and makes the resulting line search robust for
an initial implementation.
A list with coords, trace, frames,
prepared, and score.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.landmark.geodesic.kk( cycle_edges, n = 6, local.nbrs = 2, landmark.count = 2 ) fit <- landmark.geodesic.kk(initial, prepared = prepared, max.iter = 1)cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) prepared <- prepare.landmark.geodesic.kk( cycle_edges, n = 6, local.nbrs = 2, landmark.count = 2 ) fit <- landmark.geodesic.kk(initial, prepared = prepared, max.iter = 1)
Use one extraction step for ordinary layouts, traces, MDS fits, and supported refinement results. Existing return types and direct field access are unchanged.
layout.coords(x)layout.coords(x)
x |
A numeric coordinate matrix, a |
For traces the final frame is selected. For MDS and refinement fits
the fitted coords are selected. A plain list containing only coords is
not a recognized result; pass that matrix explicitly instead.
Keep graph vertex order when reusing coordinates. MDS result fields method,
coords, diagnostics, and metadata remain directly available. Stopping
information in metadata is method-dependent. Trace $final and refinement
$coords remain supported. Prepared caches and internal state fields are
version-dependent: rebuild them when the graph or package contract changes.
The coordinate matrix, unchanged, including vertex order, dimensions, dimnames, and attributes. No projection, alignment, scaling, or scoring is performed. Malformed, ambiguous, or unsupported objects produce an error.
grip(), trace.grip(), classical.mds(), geodesic.kk()
edges <- edges.path(6) fits <- list(grip(edges, n = 6, dim = 2, seed = 1), trace.grip(edges, n = 6, dim = 2, seed = 1), classical.mds(edges = edges, n = 6)) first <- layout.coords(fits[[1]]) coords <- lapply(fits, layout.coords) plot.layout(coords[[1]], edges = edges) vapply(coords, function(z) score.layout(z, edges = edges, n = 6, sample.size.stress = 15, stress.seed = 1, edge.crossings = "never")$sampled.stress, numeric(1))edges <- edges.path(6) fits <- list(grip(edges, n = 6, dim = 2, seed = 1), trace.grip(edges, n = 6, dim = 2, seed = 1), classical.mds(edges = edges, n = 6)) first <- layout.coords(fits[[1]]) coords <- lapply(fits, layout.coords) plot.layout(coords[[1]], edges = edges) vapply(coords, function(z) score.layout(z, edges = edges, n = 6, sample.size.stress = 15, stress.seed = 1, edge.crossings = "never")$sampled.stress, numeric(1))
This function preserves the original local-force wrapper and historical
default values that were previously exposed as grip().
Use it for backwards-compatible comparisons or when you explicitly want the
pre-global-repulsion behavior.
legacy.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 20, final.rounds = 25, num.init = 36, num.nbrs = 10, r = 0.15, s = 3, repulsion.factor = 1, tinit.factor = 6, seed = 6, disconnected = c("components", "error") )legacy.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 20, final.rounds = 25, num.init = 36, num.nbrs = 10, r = 0.15, s = 3, repulsion.factor = 1, tinit.factor = 6, seed = 6, disconnected = c("components", "error") )
edges |
Two-column integer matrix of edges (1-based vertex ids).
Supply either |
n |
Number of vertices, a finite positive integer. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Optional parallel list of edge weights (edge lengths). If NULL, all edges are treated as weight 1. All weights must be finite and strictly positive. |
edge.weights |
Optional vector of edge weights for |
dim |
Layout dimension (2 or 3). Default is 3. |
placement |
Initial placement strategy. "circle" is only used for 2D. |
preset |
Optional tuning preset. |
rounds |
Initial rounds for refinement. |
final.rounds |
Final rounds for refinement. |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of graph-distance neighbors retained for local refinement at each filtration level. |
r |
Main local temperature adaptation rate in |
s |
Non-negative boost factor applied when successive displacements have a consistent direction. |
repulsion.factor |
Non-negative multiplier applied to GRIP's
finest-level repulsive force scale. |
tinit.factor |
Initial temperature factor. |
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
disconnected |
How to handle disconnected graphs:
|
A numeric matrix with n rows and dim columns.
Gajer, P. and Kobourov, S.G. (2002). GRIP: Graph dRawing with Intelligent Placement. Journal of Graph Algorithms and Applications, 6(3), 203–224. doi:10.7155/jgaa.00052.
Gajer, P., Goodrich, M.T. and Kobourov, S.G. (2004). A multi-dimensional approach to force-directed layouts of large graphs. Computational Geometry, 29(1), 3–18. doi:10.1016/j.comgeo.2004.03.014.
edges <- cbind(1:5, 2:6) coords <- legacy.grip(edges, n = 6, dim = 2, placement = "barycenter", rounds = 5, final.rounds = 5, num.init = 3, num.nbrs = 4, seed = 1) round(coords, 3)edges <- cbind(1:5, 2:6) coords <- legacy.grip(edges, n = 6, dim = 2, placement = "barycenter", rounds = 5, final.rounds = 5, num.init = 3, num.nbrs = 4, seed = 1) round(coords, 3)
Convenience constructors for connected keep-masks that can
be passed to recursive.mask.grid.surface.graph() to build generalized mask
carpets. These helpers are meant to provide explicit benchmark motifs such
as cross, border, corner, and asymmetric-hole patterns.
mask.cross(k = 5, arm.width = 1) mask.border(k = 5, thickness = 1) mask.corner( k = 5, width = 2, corner = c("top_left", "top_right", "bottom_left", "bottom_right") ) mask.asymmetric.holes(k = 5, hole.size = 1)mask.cross(k = 5, arm.width = 1) mask.border(k = 5, thickness = 1) mask.corner( k = 5, width = 2, corner = c("top_left", "top_right", "bottom_left", "bottom_right") ) mask.asymmetric.holes(k = 5, hole.size = 1)
k |
Mask side length. |
arm.width |
Width of the retained cross arms. |
thickness |
Border thickness for |
width |
Side length of the retained corner block for
|
corner |
Which corner to retain in |
hole.size |
Side length of each removed interior hole block for
|
The returned masks use standard matrix display orientation: rows run from top to bottom and columns run from left to right.
A logical keep-mask.
asymmetric <- mask.asymmetric.holes(k = 5, hole.size = 1) border <- mask.border(k = 5, thickness = 1) corner <- mask.corner(k = 5, width = 2, corner = "top_left") cross <- mask.cross(k = 5, arm.width = 1)asymmetric <- mask.asymmetric.holes(k = 5, hole.size = 1) border <- mask.border(k = 5, thickness = 1) corner <- mask.corner(k = 5, width = 2, corner = "top_left") cross <- mask.cross(k = 5, arm.width = 1)
Convenience wrappers around recursive.cube.mask.surface.*() using the
classic Menger-sponge keep-mask. These helpers
provide a named cubical 3D benchmark family whose vertices are occupied
subcubes and whose edges connect face-adjacent occupied cells.
menger.sponge.surface.graph( level = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") )menger.sponge.surface.graph( level = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") )
level |
Recursion depth. Must be at least |
surface |
Cube-mask geometry family. One of |
amplitude |
Finite deformation amplitude. |
freq |
Positive modulation frequency used only when
|
twist |
Finite twist strength used only when
|
x.scale |
Positive horizontal scaling applied to the canonical cube coordinates. |
y.scale |
Positive vertical scaling applied to the canonical cube coordinates. |
z.scale |
Positive depth scaling applied to the canonical cube coordinates. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z, where
n = 20^level.
menger.sponge.surface.graph() returns the same components as
recursive.cube.mask.surface.graph(), with family set to
"menger.sponge" and a family-specific class and label.
sponge <- menger.sponge.surface.graph(level = 1)sponge <- menger.sponge.surface.graph(level = 1)
Convenience helpers that lift a rectangular mesh parameter grid into
and use the induced Euclidean edge lengths as positive
graph weights. These helpers are intended for benchmark families where the
topology is a plain mesh but the intended metric comes from a curved ambient
geometry.
mesh.surface.graph( h, w = h, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, connectivity = c("orthogonal", "diagonal"), normalize = c("median", "mean", "none") )mesh.surface.graph( h, w = h, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, connectivity = c("orthogonal", "diagonal"), normalize = c("median", "mean", "none") )
h |
Number of rows. |
w |
Number of columns. Defaults to |
surface |
Surface family used for the lift. One of |
amplitude |
Finite numeric amplitude controlling the non-flat displacement. |
freq.u |
Positive ripple frequency in the horizontal parameter
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical parameter direction.
Used only when |
x.scale |
Positive horizontal scaling of the parameter domain. |
y.scale |
Positive vertical scaling of the parameter domain. |
connectivity |
Mesh neighborhood rule. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component contains the 3D coordinates of the lifted grid.
mesh.surface.graph() returns a reusable weighted-graph bundle containing the
mesh edges, induced edge weights, the 3D surface coordinates, and the 2D
parameter coordinates.
The coords_surface component is an n x 3 numeric matrix with
columns x, y, and z.
mesh.surface.graph() returns a list with components:
edges: the undirected mesh edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the 2D parameter-grid coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "mesh",
surface: the chosen surface name,
connectivity: the chosen mesh connectivity rule,
label: a human-readable family label.
mesh <- mesh.surface.graph(4, 5, surface = "saddle")mesh <- mesh.surface.graph(4, 5, surface = "saddle")
metric.mds() fits Euclidean coordinates to graph distances. The default
approximation = "full" minimizes raw stress over all shortest-path
distances, using native stochastic gradient descent (SGD, the default)
or smacof::mds(type = "ratio"). With approximation = "sparse",
pivots and sparse SGD approximate long-range interactions without
constructing an all-pairs distance matrix.
Only the SMACOF backend requires the optional smacof package.
Before version 0.2.0.9000,
this name performed classical scaling; use classical.mds() to retain that
behavior. The add and eig arguments belong to classical.mds() only.
metric.mds( prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2L, init = c("classical", "random"), n.init = 1L, max.iter = 1000L, eps = 1e-08, seed = 1L, diagnostics = TRUE, scale.mode = c("profiled", "identity"), distance.floor = 1e-08, edge.length.epsilon = 1e-08, band.quantiles = c(1/3, 2/3), backend = c("sgd", "smacof"), sgd.control = list(), pair.weights = c("uniform", "inverse_squared"), approximation = c("full", "sparse"), sparse.control = list() )metric.mds( prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 2L, init = c("classical", "random"), n.init = 1L, max.iter = 1000L, eps = 1e-08, seed = 1L, diagnostics = TRUE, scale.mode = c("profiled", "identity"), distance.floor = 1e-08, edge.length.epsilon = 1e-08, band.quantiles = c(1/3, 2/3), backend = c("sgd", "smacof"), sgd.control = list(), pair.weights = c("uniform", "inverse_squared"), approximation = c("full", "sparse"), sparse.control = list() )
prepared |
An all-pairs prepared graph object containing
|
edges |
Two-column integer edge matrix used when |
n |
Finite positive integer vertex count. When supplied with a prepared object, it must match the stored graph size. |
adj.list |
Optional adjacency list used when |
weight.list |
Optional edge-weight list parallel to |
edge.weights |
Optional positive edge weights parallel to |
dim |
Target embedding dimension. Values greater than 3 are supported for GMDS and edge-KK workflows. |
init |
|
n.init |
Positive integer number of starts, including the first start. Sparse MDS currently requires one start. |
max.iter |
Positive integer iteration limit per start. For SGD, the number of complete passes over full or retained sparse pairs. Defaults to 1000 for full MDS and 30 for sparse MDS. The sparse default is a provisional calibration choice, not a convergence criterion. |
eps |
Positive SMACOF tolerance for the change in normalized stress. Do not supply this argument for SGD, which runs its prescribed schedule. |
seed |
Integer random seed, or |
diagnostics |
Attach the common GMDS diagnostic panel. With |
scale.mode |
Diagnostic scale policy: |
distance.floor |
Positive floor for relative residuals. |
edge.length.epsilon |
Small stabilizer for fixed-path embedded lengths. |
band.quantiles |
Two quantiles splitting graph distances into short, mid, and long bands. |
backend |
|
sgd.control |
Named list used only with |
pair.weights |
|
approximation |
|
sparse.control |
Named list used only with |
With approximation = "full", the objective is
By default, all pair weights are one. With pair.weights = "inverse_squared",
, as in Zheng et al. (2018); stress is then the
sum of squared relative distance errors. Edge weights define graph distances;
pair.weights separately specifies their importance in the stress objective.
Both backends, coordinate rescaling, checkpoint/start selection, and stress
metadata use the selected weights. The common score.gmds() diagnostic panel
retains its own definitions and does not become a weighted objective report.
SMACOF normalizes targets internally. Returned coordinates are rescaled to
minimize raw stress against the original input distances. scale.mode
controls the optional diagnostic panel only, not the optimization objective.
Target-normalized raw stress and scale-profiled Stress-1 select the same
shapes when global scale is free and pair weights agree. Their values at a
fixed coordinate scale need not agree. Both the literal and target-profiled
Stress-1 values are independently calculated in metadata; the backend's
own reported stress is retained separately in the start summaries.
The first run uses init; subsequent runs use random configurations.
The smallest achieved raw stress selects the result. A backend result that
increases stress beyond numerical tolerance is rejected in favor of its
scaled start and marked accordingly. Failed starts are recorded, and all
failing starts cause an error. Iteration limits are not convergence or global
optimality certificates. Collinear or planar starts may remain in their
initial span; use multiple starts to investigate this sensitivity.
Newly prepared graph objects supply symmetric strict shortest distances, separately from retained-route lengths used in path diagnostics. Rebuild older cached preparations if their near-tie distance matrix is asymmetric.
Targets must be finite, symmetric, and nonnegative, with zero diagonal and
at least one positive distance. Missing and infinite distances are rejected.
Inverse-squared weighting requires strictly positive off-diagonal targets;
zero distances are rejected, not floored. Uniform weighting still allows zero
distances. Extreme ratios that overflow or underflow the normalized weights
are rejected. Supplied starts may have coincident points but must not be wholly collapsed.
Full MDS uses dense all-pairs matrices; use approximation = "sparse"
when that preparation is too large. Sparse behavior is described below.
A "grip_gmds_layout" object with method "metric_mds".
metadata$engine and metadata$approximation identify both choices.
In full mode, metadata records the objective, backend/version, achieved raw stress,
weighted target-normalized RMSE, both weighted Stress-1 conventions, selected start,
coordinate scale multiplier, and per-start losses and stopping information.
SGD adds per-start elapsed seconds (native fitting including scoring),
native seeds, pair-update counts, best epochs, and checkpoint histories in
metadata$sgd. Histories use RMS-normalized target-distance units and include
both raw and scale-profiled stress. Internally, inverse-squared weights are
1 / (distance / input_rms_distance)^2; the corresponding stress is already
dimensionless. Uniform raw stress is converted to squared input-distance
units for public metadata. Weighted target-normalized RMSE takes the square
root of the ratio of stress to the sum of weighted squared target distances.
SGD reports iteration_limit and converged = FALSE when its
schedule finishes, including when an earlier checkpoint is returned.
Every pass visits all unordered pairs in shuffled order. The pair step is
clipped at min(rate * normalized_pair_weight, 1). Rates use RMS-normalized
distance units for both weighting choices; changing input distance units
therefore preserves the optimization trajectory up to scale. The default
schedule is shared across weighting choices, not a reproduction of the
graph-dependent annealing schedule used in Zheng et al. (2018). Symmetric clipped
updates follow Zheng et al. (2018); the hybrid exponential/harmonic schedule
follows Hangan et al. (2026). The terminal epoch is always scored. The best
independently scored checkpoint, including initialization, is retained using
scale-profiled stress; checkpoint scoring does not rescale the ongoing search.
The R wrapper independently rescales and recomputes its returned stress.
The exponential schedule's final rate is its boundary value after the planned
passes, not its last applied rate. The hybrid schedule switches after
floor(switch.ratio * max.iter) passes, at one tenth the initial rate
(or the initial rate if the switch is immediate). Its harmonic segment
approaches final.rate at the boundary only when the switch rate exceeds
final.rate; otherwise that segment stays constant at the switch rate.
With switch.ratio = 1, no harmonic segment occurs and final.rate is unused.
Coincident points with positive target distance are separated along a seeded
direction; zero targets are not floored. Without such collisions, updates
preserve a deficient initial affine span. Use full-dimensional random starts
to examine this sensitivity. This backend retains quadratic pair storage and
work per pass. It does not validate the supplied graph distances.
Sparse SGD implements the asymmetric updates of Zheng et al. (2018), Algorithm 2, based on the model of Ortmann et al. (2017). The graph must have positive finite edge lengths and be connected. Disconnected graphs are rejected without repair. Pivots are chosen with probability proportional to distance to the nearest selected pivot, starting from a uniform random vertex. Graph lengths are normalized by their maximum before shortest-path calculations. Exact distance ties in region assignment go to the earliest selected pivot. Near floating-point boundaries, general weighted graphs can still be sensitive to arithmetic. Each nonadjacent vertex receives an influence from a pivot weighted by the number of vertices in that pivot's region within half their separation, divided by squared separation. The reverse influence can be zero or different. Edges have inverse-squared weights at both endpoints.
Edge targets are the supplied edge lengths, as in the upstream sparse implementation. For a weighted edge with a shorter alternative route, that target differs from the shortest-path target of full MDS. Exact full-pivot update parity requires every edge to be a shortest path, as with unit lengths or Euclidean chord lengths, and matched starts, rates and order.
Targets are normalized by RMS over the retained unordered pairs; endpoint weights use the same units. The default hybrid schedule is grip's existing schedule, not the paper's weight-dependent annealing. The terminal iterate is returned, centered and converted back to input units, with no fitted scale. A checkpoint proxy averages the two endpoint weights for each pair. Asymmetric updates are not claimed to follow the gradient of that proxy, or to decrease it monotonically. This diagnostic is not full stress or equation (19) of Zheng et al. Use independent distance evaluation to compare sparse and full layouts. No dense diagnostics or classical initialization run implicitly.
Sparse results share the metric_mds method name.
coords is the terminal layout. prepared contains an edge-only graph,
without a distance matrix. metadata$sparse records retained pairs,
original-unit targets, endpoint multiplicities, selected pivots and region
owners. Metadata also records seeds, controls, preparation/fitting seconds,
native workspace estimates (separately checked for preparation and fitting),
sparse_proxy_stress, its normalized root
error, and termination = "iteration_limit", converged = FALSE.
trace reports checkpoint proxy stress, epochs, rates and pair updates.
Start with vignette("function-guide", package = "grip")
to choose a layout, diagnostic, or reference comparison. List installed
guides with vignette(package = "grip").
Ortmann, M., Klimenta, M. and Brandes, U. (2017). A Sparse Stress Model. doi:10.7155/jgaa.00440. Zheng, J. X., Pawar, S. and Goodman, D. F. (2018). Graph Drawing by Stochastic Gradient Descent. doi:10.1109/TVCG.2018.2859997. Hangan, D., Kobourov, S. and Miller, J. (2026). Bridging Graph Drawing and Dimensionality Reduction with Stochastic Stress Optimization. https://arxiv.org/abs/2605.00641.
classical.mds(), edge.kk(), smacof::mds()
prepared <- prepare.graph.geodesic.mds(edges.cycle(6), n = 6) fit <- suppressWarnings(metric.mds(prepared = prepared, dim = 2, max.iter = 30)) fit$metadata$raw_stress fit$metadata$termination # Schedule completion is not a convergence certificate. # Schedule completion is reported explicitly, not as convergence. fit <- suppressWarnings(metric.mds(edges = edges.cycle(8), n = 8, dim = 3, init = "random", backend = "sgd", max.iter = 30, diagnostics = FALSE)) fit$metadata$engine fit$metadata$target_normalized_rmse sparse <- metric.mds(edges = edges.path(30), dim = 3, approximation = "sparse", sparse.control = list(n.pivots = 5)) sparse$metadata$sparse_proxy_stressprepared <- prepare.graph.geodesic.mds(edges.cycle(6), n = 6) fit <- suppressWarnings(metric.mds(prepared = prepared, dim = 2, max.iter = 30)) fit$metadata$raw_stress fit$metadata$termination # Schedule completion is not a convergence certificate. # Schedule completion is reported explicitly, not as convergence. fit <- suppressWarnings(metric.mds(edges = edges.cycle(8), n = 8, dim = 3, init = "random", backend = "sgd", max.iter = 30, diagnostics = FALSE)) fit$metadata$engine fit$metadata$target_normalized_rmse sparse <- metric.mds(edges = edges.path(30), dim = 3, approximation = "sparse", sparse.control = list(n.pivots = 5)) sparse$metadata$sparse_proxy_stress
misf.geodesic.kk() runs a multiscale MISF-based geodesic-KK
pipeline. It solves the top MISF graph with either full GKK or sparse LGKK,
inserts lower-level vertices with the existing MISF placement helpers, refines
each active MISF level under a GKK/LGKK objective, and finishes with a final
full-graph polish.
misf.geodesic.kk( prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = NULL, num.init = 24L, num.nbrs = 20L, dim = NULL, top.level.pair.mode = NULL, top.level.full.limit = NULL, top.level.local.nbrs = NULL, top.level.landmark.count = NULL, top.level.restarts = NULL, top.level.max.iter = NULL, top.level.init = NULL, insertion.anchor.policy = NULL, insertion.anchor.count = NULL, insertion.anchor.weight.mode = NULL, insertion.max.iter = NULL, insertion.mode = NULL, insertion.layout.k = NULL, insertion.weighted.preset = NULL, insertion.grip.args = NULL, insertion.weighted.args = NULL, insertion.fr.niter = NULL, refinement.pair.mode = NULL, refinement.full.limit = NULL, refinement.local.nbrs = NULL, refinement.landmark.count = NULL, refinement.anchor.weight = NULL, refinement.anchor.weight.end = NULL, refinement.continuation = NULL, refinement.max.iter = NULL, final.pair.mode = NULL, final.full.limit = NULL, final.local.nbrs = NULL, final.landmark.count = NULL, final.max.iter = NULL, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, recenter = TRUE, return.trace = FALSE, return.frames = FALSE, seed = 6L )misf.geodesic.kk( prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = NULL, num.init = 24L, num.nbrs = 20L, dim = NULL, top.level.pair.mode = NULL, top.level.full.limit = NULL, top.level.local.nbrs = NULL, top.level.landmark.count = NULL, top.level.restarts = NULL, top.level.max.iter = NULL, top.level.init = NULL, insertion.anchor.policy = NULL, insertion.anchor.count = NULL, insertion.anchor.weight.mode = NULL, insertion.max.iter = NULL, insertion.mode = NULL, insertion.layout.k = NULL, insertion.weighted.preset = NULL, insertion.grip.args = NULL, insertion.weighted.args = NULL, insertion.fr.niter = NULL, refinement.pair.mode = NULL, refinement.full.limit = NULL, refinement.local.nbrs = NULL, refinement.landmark.count = NULL, refinement.anchor.weight = NULL, refinement.anchor.weight.end = NULL, refinement.continuation = NULL, refinement.max.iter = NULL, final.pair.mode = NULL, final.full.limit = NULL, final.local.nbrs = NULL, final.landmark.count = NULL, final.max.iter = NULL, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, initial.step = 1, step.shrink = 0.5, armijo.factor = 1e-04, grad.tol = 1e-08, min.step = 1e-08, recenter = TRUE, return.trace = FALSE, return.frames = FALSE, seed = 6L )
prepared |
Optional prepared object. This can be either a full geodesic-KK prepared object or a MISF-GKK prepared object. |
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to |
tie.mode |
Shortest-path aggregation mode inherited from
|
num.init |
Target top-level active-set size passed to |
num.nbrs |
Per-level local-neighborhood schedule metadata passed to
|
dim |
Target embedding dimension ( |
top.level.pair.mode |
Optional override for the top-level pair policy. |
top.level.full.limit |
Optional override for the top-level exact/sparse threshold. |
top.level.local.nbrs |
Optional override for the sparse top-level local neighborhood size. |
top.level.landmark.count |
Optional override for the sparse top-level landmark count. |
top.level.restarts |
Number of top-level restarts used by the coarse MISF-GKK solve. |
top.level.max.iter |
Top-level iteration budget. |
top.level.init |
Optional override for the top-level initializer. |
insertion.anchor.policy |
Optional insertion anchor policy. |
insertion.anchor.count |
Optional insertion anchor count. |
insertion.anchor.weight.mode |
Optional insertion anchor weighting mode. |
insertion.max.iter |
Optional per-vertex insertion iteration budget. |
insertion.mode |
Optional insertion warm-start mode. |
insertion.layout.k |
Optional active-level layout graph size used by layout-based insertion modes. |
insertion.weighted.preset |
Optional preset passed to weighted GRIP insertion. |
insertion.grip.args |
Optional named list of extra arguments passed to combinatorial GRIP insertion. |
insertion.weighted.args |
Optional named list of extra arguments for weighted GRIP insertion. |
insertion.fr.niter |
Optional FR iteration budget for FR-based insertion. |
refinement.pair.mode |
Optional active-level pair policy. |
refinement.full.limit |
Optional active-level exact/sparse threshold. |
refinement.local.nbrs |
Optional active-level sparse local neighborhood size. |
refinement.landmark.count |
Optional active-level sparse landmark count. |
refinement.anchor.weight |
Optional initial anchor weight used to pin inactive and coarser-level vertices during KK refinement. |
refinement.anchor.weight.end |
Optional final anchor weight used at the end of the active-level continuation schedule. |
refinement.continuation |
Optional continuation schedule used for the active-level anchor penalty. |
refinement.max.iter |
Optional active-level refinement iteration budget. |
final.pair.mode |
Optional final full-graph pair policy. |
final.full.limit |
Optional final full-graph exact/sparse threshold. |
final.local.nbrs |
Optional final full-graph sparse local neighborhood size. |
final.landmark.count |
Optional final full-graph sparse landmark count. |
final.max.iter |
Optional final polish iteration budget. |
stiffness |
Global stiffness constant \(K\). |
distance.floor |
Small positive floor used in
|
edge.length.epsilon |
Small positive stabilizer added inside each embedded edge length. |
initial.step |
Initial line-search step size. |
step.shrink |
Multiplicative shrink factor in |
armijo.factor |
Non-negative Armijo decrease constant. |
grad.tol |
Non-negative stopping tolerance on the gradient norm. |
min.step |
Positive minimum accepted line-search step before giving up. |
recenter |
If |
return.trace |
If |
return.frames |
If |
seed |
Optional integer seed reused for MISF extraction. |
A list with coords, prepared, the per-stage multiscale results,
the stage trace, optional trace/frame details, timing, and the final MISF
score summary.
mesh_edges <- edges.mesh(4, 4) fit <- misf.geodesic.kk( edges = mesh_edges, n = 16, num.init = 4, dim = 2, top.level.restarts = 2, top.level.max.iter = 3, insertion.mode = "geodesic", insertion.max.iter = 6, refinement.pair.mode = "auto", refinement.full.limit = 4, refinement.max.iter = 3, final.pair.mode = "landmark", final.full.limit = 4, final.max.iter = 3, return.trace = TRUE, seed = 1 )mesh_edges <- edges.mesh(4, 4) fit <- misf.geodesic.kk( edges = mesh_edges, n = 16, num.init = 4, dim = 2, top.level.restarts = 2, top.level.max.iter = 3, insertion.mode = "geodesic", insertion.max.iter = 6, refinement.pair.mode = "auto", refinement.full.limit = 4, refinement.max.iter = 3, final.pair.mode = "landmark", final.full.limit = 4, final.max.iter = 3, return.trace = TRUE, seed = 1 )
occupied.mesh.surface.graph() builds a finite occupied-grid graph on the
retained cells of a rectangular occupancy matrix and lifts those cells into
using the same
"saddle", "paraboloid", and "ripple" families used
for regular meshes.
occupied.mesh.surface.graph( keep, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, connectivity = c("orthogonal", "diagonal"), normalize = c("median", "mean", "none") )occupied.mesh.surface.graph( keep, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, connectivity = c("orthogonal", "diagonal"), normalize = c("median", "mean", "none") )
keep |
Logical or numeric occupancy matrix. Non-zero entries are kept. |
surface |
Surface family used for the lift. One of |
amplitude |
Finite numeric amplitude controlling the non-flat displacement. |
freq.u |
Positive ripple frequency in the horizontal parameter
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical parameter direction.
Used only when |
x.scale |
Positive horizontal scaling of the parameter domain. |
y.scale |
Positive vertical scaling of the parameter domain. |
connectivity |
Mesh neighborhood rule passed to |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
occupied.mesh.surface.graph() returns a list with components:
edges: the occupied-cell mesh edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the 2D parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "occupied.mesh",
surface: the chosen surface name,
connectivity: the chosen occupied-mesh connectivity rule,
keep: the logical occupancy matrix,
label: a human-readable family label.
keep <- matrix(TRUE, nrow = 4, ncol = 5) keep[2, 3] <- FALSE occupied <- occupied.mesh.surface.graph(keep, surface = "paraboloid")keep <- matrix(TRUE, nrow = 4, ncol = 5) keep[2, 3] <- FALSE occupied <- occupied.mesh.surface.graph(keep, surface = "paraboloid")
Converts one row of the summary data frame returned by
compare.layouts into a named list of parameters suitable
for passing to grip or back into a
compare.layouts(candidates = ...) call.
params.from.summary(summary.row)params.from.summary(summary.row)
summary.row |
A one-row data frame (or the first row is used) from the
|
A named list with elements placement, rounds,
final_rounds, num_init, num_nbrs, r,
s, repulsion_factor, tinit_factor, and optionally
preset (included only when the summary row records a non-empty
preset).
edges <- edges.path(5) cmp <- compare.layouts(edges, n = 5, dim = 2, candidates = "default", seeds = 1L) params <- params.from.summary(cmp$summary[1, ]) coords <- do.call( grip, c(list(edges = edges, n = 5, dim = 2, seed = 42L), params) ) round(coords, 2)edges <- edges.path(5) cmp <- compare.layouts(edges, n = 5, dim = 2, candidates = "default", seeds = 1L) params <- params.from.summary(cmp$summary[1, ]) coords <- do.call( grip, c(list(edges = edges, n = 5, dim = 2, seed = 42L), params) ) round(coords, 2)
Convenience constructors for finite occupied grids with non-random holes or
channels. These matrices can be passed to
occupied.mesh.surface.graph().
keep.periodic.holes( h, w = h, hole.period = 4, hole.height = 1, hole.width = hole.height, row.offset = 2, col.offset = 2 ) keep.staggered.windows( h, w = h, window.height = 1, window.width = 2, row.period = 4, col.period = 5, row.offset = 2, col.offset = 2 ) keep.slit.channels( h, w = h, orientation = c("vertical", "horizontal"), slit.period = 5, slit.width = 1, bridge.spacing = 4, bridge.size = 1, offset = 2 ) keep.asymmetric.notches(h, w = h, notch.depth = 3, notch.width = 2)keep.periodic.holes( h, w = h, hole.period = 4, hole.height = 1, hole.width = hole.height, row.offset = 2, col.offset = 2 ) keep.staggered.windows( h, w = h, window.height = 1, window.width = 2, row.period = 4, col.period = 5, row.offset = 2, col.offset = 2 ) keep.slit.channels( h, w = h, orientation = c("vertical", "horizontal"), slit.period = 5, slit.width = 1, bridge.spacing = 4, bridge.size = 1, offset = 2 ) keep.asymmetric.notches(h, w = h, notch.depth = 3, notch.width = 2)
h |
Number of rows. |
w |
Number of columns. Defaults to |
hole.period |
Spacing between periodic holes. |
hole.height |
Height of each removed rectangular hole. |
hole.width |
Width of each removed rectangular hole. |
row.offset |
Starting row index for the first removed block. |
col.offset |
Starting column index for the first removed block. |
window.height |
Height of each staggered removed window. |
window.width |
Width of each staggered removed window. |
row.period |
Vertical spacing between staggered window bands. |
col.period |
Horizontal spacing between staggered windows within a band. |
orientation |
Whether slit channels run |
slit.period |
Spacing between repeated slit channels. |
slit.width |
Width of each slit channel. |
bridge.spacing |
Spacing between preserved bridge segments. |
bridge.size |
Size of each preserved bridge segment along a slit. |
offset |
Starting row or column index for the first slit channel. |
notch.depth |
Depth of each asymmetric notch cut from a boundary. |
notch.width |
Width of the notched opening along that boundary. |
A logical occupancy matrix whose TRUE entries represent
retained cells.
notches <- keep.asymmetric.notches(7, 8, notch.depth = 2, notch.width = 2) holes <- keep.periodic.holes(7, 8, hole.period = 3) slits <- keep.slit.channels(7, 8, slit.period = 3) windows <- keep.staggered.windows(7, 8, row.period = 3, col.period = 4)notches <- keep.asymmetric.notches(7, 8, notch.depth = 2, notch.width = 2) holes <- keep.periodic.holes(7, 8, hole.period = 3) slits <- keep.slit.channels(7, 8, slit.period = 3) windows <- keep.staggered.windows(7, 8, row.period = 3, col.period = 4)
For 2D layouts, draws vertices and edges using base graphics.
For 3D layouts, the behaviour depends on the projection argument:
"rgl" (default)Opens an interactive rgl scene when
that package is installed. Falls back to "ortho" with a warning
if rgl is not available.
"ortho"Projects the 3D coordinates to 2D with
project.3d and draws them with base graphics, giving
a static figure suitable for vignettes and non-interactive reports.
## S3 method for class 'layout' plot(x, ..., edges = NULL, projection = c("rgl", "ortho"), azimuth = 35, elevation = 22, vertex.col = "black", edge.col = "gray70")## S3 method for class 'layout' plot(x, ..., edges = NULL, projection = c("rgl", "ortho"), azimuth = 35, elevation = 22, vertex.col = "black", edge.col = "gray70")
x |
Numeric coordinate matrix with at least two columns. |
... |
For static plots, base graphics options override defaults, including
|
edges |
Optional two-column matrix of edges (1-based vertex ids). |
projection |
Character string controlling how 3D layouts are displayed:
|
azimuth |
Rotation around the vertical axis in degrees. Only used when
|
elevation |
Rotation around the horizontal axis in degrees. Only used
when |
vertex.col |
Colour(s) for the vertices. Recycled to match the number
of vertices. Default |
edge.col |
Colour for the edges. Default |
NULL (called for side effects).
edges <- cbind(1:5, 2:6) coords <- grip(edges, n = 6, dim = 2, placement = "barycenter", rounds = 5, final.rounds = 5, num.init = 3, num.nbrs = 4, seed = 1) plot.layout(coords, edges, main = "Path graph", pch = 16, cex = 0.8)edges <- cbind(1:5, 2:6) coords <- grip(edges, n = 6, dim = 2, placement = "barycenter", rounds = 5, final.rounds = 5, num.init = 3, num.nbrs = 4, seed = 1) plot.layout(coords, edges, main = "Path graph", pch = 16, cex = 0.8)
Convenience wrappers around recursive.cube.mask.surface.*() for three
named porous cubical families: a periodic tunnel lattice, an asymmetric
cavity family, and a deterministic channel network. Each family uses a
reusable base keep-array and then recurses it in exactly the same way as the
generic cube-mask helpers.
cube.periodic.tunnels.surface.graph( level = 2, side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") ) cube.asymmetric.cavities.surface.graph( level = 2, side = 5, cavity.size = 2, pocket.size = max(1L, cavity.size - 1L), surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") ) cube.channel.network.surface.graph( level = 2, side = 5, channel.width = 1, branch.offset = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") )cube.periodic.tunnels.surface.graph( level = 2, side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") ) cube.asymmetric.cavities.surface.graph( level = 2, side = 5, cavity.size = 2, pocket.size = max(1L, cavity.size - 1L), surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") ) cube.channel.network.surface.graph( level = 2, side = 5, channel.width = 1, branch.offset = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") )
level |
Recursion depth. Must be at least |
side |
Side length of the base cubic keep-array. |
tunnel.width |
Width of each removed tunnel band. |
tunnel.period |
Spacing between successive tunnel bands. |
tunnel.offset |
Starting index of the first tunnel band. |
surface |
Cube-mask geometry family. One of |
amplitude |
Finite deformation amplitude. |
freq |
Positive modulation frequency used only when
|
twist |
Finite twist strength used only when
|
x.scale |
Positive horizontal scaling applied to the canonical cube coordinates. |
y.scale |
Positive vertical scaling applied to the canonical cube coordinates. |
z.scale |
Positive depth scaling applied to the canonical cube coordinates. |
normalize |
Normalization applied to the induced edge lengths. One of
|
cavity.size |
Side length of the larger interior cavity block. |
pocket.size |
Side length of the smaller secondary cavity block. |
channel.width |
Width of each removed channel in the channel-network family. |
branch.offset |
Interior offset of the extra branch channel in the channel-network family. |
Each graph bundle's coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
Each *.surface.graph() helper returns the same components as
recursive.cube.mask.surface.graph(), with a family-specific
family field, class, and label.
asymmetric <- cube.asymmetric.cavities.surface.graph( level = 1, side = 5, cavity.size = 1, pocket.size = 1 ) channels <- cube.channel.network.surface.graph( level = 1, side = 5, channel.width = 1, branch.offset = 2 ) tunnels <- cube.periodic.tunnels.surface.graph( level = 1, side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 1 )asymmetric <- cube.asymmetric.cavities.surface.graph( level = 1, side = 5, cavity.size = 1, pocket.size = 1 ) channels <- cube.channel.network.surface.graph( level = 1, side = 5, channel.width = 1, branch.offset = 2 ) tunnels <- cube.periodic.tunnels.surface.graph( level = 1, side = 5, tunnel.width = 1, tunnel.period = 2, tunnel.offset = 1 )
prepare.edge.kk() validates an undirected weighted graph and
returns the lightweight prepared object used by
edge.kk() when only graph-edge targets are
needed. Unlike prepare.graph.geodesic.mds(), this helper
does not compute all-pairs shortest paths, path caches, or a dense graph
distance matrix.
prepare.edge.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL )prepare.edge.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
Use this helper when a starting layout is already available, for example from
grip(..., metric = "edge_length"), and the next step is
scalable edge-KK
local repair. Edge-only objects support edge-fidelity diagnostics through
score.gmds(); all-pairs GMDS path and chord
diagnostics are unavailable and are reported as NA.
A lightweight prepared object of class
"grip_edge_kk_prepared" layered on the common
"grip_gmds_prepared" graph class. It contains canonical graph
edges and edge targets but no all-pairs geodesic cache.
cycle_edges <- edges.cycle(6) prepared <- prepare.edge.kk(cycle_edges, n = 6)cycle_edges <- edges.cycle(6) prepared <- prepare.edge.kk(cycle_edges, n = 6)
prepare.geodesic.kk() builds the deterministic all-pairs shortest
path cache needed to evaluate or optimize the full geodesic Kamada–Kawai
objective repeatedly on the same connected graph.
prepare.geodesic.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = c("single", "average") )prepare.geodesic.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = c("single", "average") )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
tie.mode |
Shortest-path aggregation mode. |
For each unordered vertex pair, the prepared object stores either one
deterministic chosen graph shortest path (tie.mode = "single") or the
exact uniform average over all tied shortest paths
(tie.mode = "average"), together with the graph distance and the
corresponding cached edge realization. This is the full all-pairs analogue of
the sparse landmark cache used by
prepare.landmark.geodesic.kk().
A list with the all-pairs graph distances, chosen paths, and cached
path-edge realizations. The object has class "grip_gkk_prepared".
cycle_edges <- edges.cycle(6) prepared <- prepare.geodesic.kk(cycle_edges, n = 6)cycle_edges <- edges.cycle(6) prepared <- prepare.geodesic.kk(cycle_edges, n = 6)
prepare.graph.geodesic.mds() prepares the full all-pairs chosen
geodesic cache for an arbitrary connected weighted graph. This is the
graph-first entry point corresponding to the manuscript's definition of GMDS
on a connected weighted graph together with a chosen geodesic family
.
prepare.graph.geodesic.mds( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = c("single", "average") )prepare.graph.geodesic.mds( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = c("single", "average") )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
tie.mode |
Shortest-path aggregation mode. |
The graph can be supplied either as an edge list plus parallel weights or as an adjacency-list representation. The returned object stores the all-pairs graph distances, the chosen shortest-path family, and the flattened edge-path cache reused by the GMDS scorer and optimizer.
The all-pairs distance.matrix contains symmetric strict graph
distances. Retained-route lengths in pair_graph_distance follow the
deterministic near-tie path convention and can differ slightly from these
targets. Route selection and path diagnostics are not changed by this
distinction.
A prepared object with class "grip_gmds_prepared" layered on
top of the existing full geodesic path-cache structure.
cycle_edges <- edges.cycle(6) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6)cycle_edges <- edges.cycle(6) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6)
prepare.landmark.geodesic.kk() builds the deterministic shortest
path trees, graph-distance cache, sparse local-plus-landmark pair set, and
chosen path realizations needed to evaluate the landmark geodesic KK energy
repeatedly on the same graph. This is intended as a reusable preparation step
for experiments where many layouts of the same graph are compared.
prepare.landmark.geodesic.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, local.nbrs = 20L, landmark.count = 8L )prepare.landmark.geodesic.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, local.nbrs = 20L, landmark.count = 8L )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
local.nbrs |
Number of nearest graph-metric neighbors retained per vertex. |
landmark.count |
Number of farthest-point landmarks retained per vertex. |
The sparse set follows the implementation choice recorded in
landmark\_geodesic\_kk\_spec\_2026-03-30.tex: each vertex contributes
its local.nbrs nearest active vertices in graph distance and its
landmark.count farthest-point landmarks, both selected
deterministically.
A list with the sparse pair set, graph distances, chosen paths, and
other cached data. The object has class "grip_lgkk_prepared".
cycle_edges <- edges.cycle(6) prepared <- prepare.landmark.geodesic.kk( cycle_edges, n = 6, local.nbrs = 2, landmark.count = 2 )cycle_edges <- edges.cycle(6) prepared <- prepare.landmark.geodesic.kk( cycle_edges, n = 6, local.nbrs = 2, landmark.count = 2 )
prepare.misf.geodesic.kk() builds the prepared state for a MISF-based
geodesic-KK pipeline by layering the maximal independent set filtration
(MISF) on top of the existing full geodesic-KK cache. The prepared object
stores the graph metadata, the coarsest admissible top-level graph, the
exact and sparse top-level prepared caches, and the default controls used by
the multiscale MISF-GKK optimizer.
prepare.misf.geodesic.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = c("single", "average"), num.init = 24L, num.nbrs = 20L, dim = 2L, top.level.mode = c("solve", "skip"), top.level.pair.mode = c("auto", "full", "landmark"), top.level.full.limit = 512L, top.level.local.nbrs = 20L, top.level.landmark.count = 8L, top.level.restarts = 8L, top.level.max.iter = 16L, top.level.init = c("geometric", "cmdscale", "random"), seed = 6L )prepare.misf.geodesic.kk( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, tie.mode = c("single", "average"), num.init = 24L, num.nbrs = 20L, dim = 2L, top.level.mode = c("solve", "skip"), top.level.pair.mode = c("auto", "full", "landmark"), top.level.full.limit = 512L, top.level.local.nbrs = 20L, top.level.landmark.count = 8L, top.level.restarts = 8L, top.level.max.iter = 16L, top.level.init = c("geometric", "cmdscale", "random"), seed = 6L )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to |
tie.mode |
Shortest-path aggregation mode inherited from
|
num.init |
Target top-level active-set size passed to |
num.nbrs |
Per-level local-neighborhood schedule metadata passed to
|
dim |
Target embedding dimension ( |
top.level.mode |
Either |
top.level.pair.mode |
Pair policy for the top MISF level: |
top.level.full.limit |
Active-set size threshold used when
|
top.level.local.nbrs |
Number of nearest graph-metric neighbors retained per vertex in the sparse top-level LGKK cache. |
top.level.landmark.count |
Number of farthest-point landmarks retained per vertex in the sparse top-level LGKK cache. |
top.level.restarts |
Number of top-level restarts used by the coarse MISF-GKK solve. |
top.level.max.iter |
Top-level iteration budget. |
top.level.init |
Top-level initializer ( |
seed |
Optional integer seed reused for MISF extraction. |
An object of class "grip_misf_gkk_prepared" layered on top of the
full geodesic-KK prepared structure, with added MISF metadata, top-level
coarse-graph caches, and stored default controls for the MISF-GKK
optimizer.
edges <- edges.mesh(4, 4) prepared <- prepare.misf.geodesic.kk( edges = edges, n = 16, tie.mode = "average", num.init = 4, top.level.mode = "skip", seed = 1 ) prepared$top_level_verticesedges <- edges.mesh(4, 4) prepared <- prepare.misf.geodesic.kk( edges = edges, n = 16, tie.mode = "average", num.init = 4, top.level.mode = "skip", seed = 1 ) prepared$top_level_vertices
Reports the fitted objective, available stopping information, coordinate
dimensions, and separately labeled graph diagnostics. Missing convergence
metadata is reported as such; finite coordinates do not imply convergence.
Printing never recomputes diagnostics. Raw metric-MDS stress has squared
input-distance units. The displayed graph RMSE values are divided by the
root mean squared target distance and are dimensionless.
Extract x$coords to plot or score the coordinates.
## S3 method for class 'grip_gmds_layout' print(x, ...)## S3 method for class 'grip_gmds_layout' print(x, ...)
x |
A |
... |
Unused additional arguments. |
The input object, invisibly.
Summarizes the vertices and levels of a hop-distance MISF hierarchy.
## S3 method for class 'grip_misf' print(x, ...)## S3 method for class 'grip_misf' print(x, ...)
x |
A |
... |
Unused additional arguments. |
The input object, invisibly.
Applies a rotation defined by azimuth and elevation angles and returns the first two columns of the rotated matrix.
project.3d(coords, azimuth = 35, elevation = 22)project.3d(coords, azimuth = 35, elevation = 22)
coords |
Numeric matrix with at least 3 columns (only the first 3 are used). |
azimuth |
Rotation around the vertical axis in degrees. Default 35. |
elevation |
Rotation around the horizontal axis in degrees. Default 22. |
This is the projection used internally by plot.layout when
projection = "ortho" and is exported so that users can pre-project
coordinates for custom plotting.
A two-column numeric matrix of projected (x, y) coordinates.
edges <- edges.torus(6, 10) coords3d <- grip(edges, n = max(edges), dim = 3, preset = "torus", seed = 1) xy <- project.3d(coords3d) plot(xy, asp = 1, pch = 16, cex = 0.5)edges <- edges.torus(6, 10) coords3d <- grip(edges, n = max(edges), dim = 3, preset = "torus", seed = 1) xy <- project.3d(coords3d) plot(xy, asp = 1, pch = 16, cex = 0.5)
Convenience helpers that recursively subdivide a cube into a regular
array of subcubes according to a cubic keep-mask,
retain the selected cells at each recursion step, and deform the resulting
face-adjacency graph inside . This provides a generic
cubical 3D family that includes Menger-sponge-style cell adjacency as a
named special case.
recursive.cube.mask.surface.graph( mask, level = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") )recursive.cube.mask.surface.graph( mask, level = 2, surface = c("standard", "bulged", "twisted", "wavy"), amplitude = 0.2, freq = 2, twist = 0.6, x.scale = 1, y.scale = 1, z.scale = 1, normalize = c("median", "mean", "none") )
mask |
Cubic logical or numeric keep-array. Non-zero entries are retained at each recursive step. |
level |
Recursion depth. Must be at least |
surface |
Cube-mask geometry family. One of |
amplitude |
Finite deformation amplitude. |
freq |
Positive modulation frequency used only when
|
twist |
Finite twist strength used only when
|
x.scale |
Positive horizontal scaling applied to the canonical cube coordinates. |
y.scale |
Positive vertical scaling applied to the canonical cube coordinates. |
z.scale |
Positive depth scaling applied to the canonical cube coordinates. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The mask is interpreted as a cubic array whose first dimension runs
from top to bottom, second from left to right, and third from front to back.
Non-zero entries are retained at each recursive step.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
recursive.cube.mask.surface.graph() returns a list with components:
edges: the retained recursive cube-mask face-adjacency edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the canonical 3D voxel-center coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "recursive.cube.mask",
surface: the chosen surface name,
level: the recursion depth,
mask: the logical keep-array,
mask_side: side length of the base keep-mask,
side: side length of the fully refined cube grid,
label: a human-readable family label.
mask <- mask.cube.channel.network( side = 5, channel.width = 1, branch.offset = 2 ) cube <- recursive.cube.mask.surface.graph(mask, level = 1)mask <- mask.cube.channel.network( side = 5, channel.width = 1, branch.offset = 2 ) cube <- recursive.cube.mask.surface.graph(mask, level = 1)
Convenience helpers that recursively subdivide a square grid according to a
square keep-mask, retain the occupied cells, and then lift those cells into
. The induced Euclidean edge lengths become positive graph
weights. This provides a generic mesh-derived family that includes the
Sierpinski carpet and related masked-grid fractals such as Vicsek-style
cross families.
recursive.mask.grid.surface.graph( mask, level = 2, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )recursive.mask.grid.surface.graph( mask, level = 2, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )
mask |
Square logical or numeric keep-mask with at least one retained cell. Non-zero entries are kept at each recursive step. |
level |
Recursion depth. Must be at least |
surface |
Surface family used for the lift. One of |
amplitude |
Finite numeric amplitude controlling the non-flat displacement. |
freq.u |
Positive ripple frequency in the horizontal parameter
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical parameter direction.
Used only when |
x.scale |
Positive horizontal scaling of the parameter domain. |
y.scale |
Positive vertical scaling of the parameter domain. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The mask is interpreted in standard matrix display orientation: rows
run from top to bottom and columns run from left to right. Non-zero entries
are retained at each recursive subdivision step.
The coords.surface component contains the 3D coordinates of the
occupied cells in the same vertex order as edges.
recursive.mask.grid.surface.graph() returns a reusable weighted-graph
bundle containing the masked-grid edges, induced edge weights, the 3D
surface coordinates, and the 2D parameter coordinates of the occupied cells.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
recursive.mask.grid.surface.graph() returns a list with components:
edges: the occupied-cell masked-grid edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the 2D parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "recursive.mask.grid",
surface: the chosen surface name,
level: the recursion depth,
mask: the logical keep-mask,
mask_size: the side length of the mask,
side: the side length of the fully refined grid,
label: a human-readable family label.
grid <- recursive.mask.grid.surface.graph(mask.cross(3), level = 1)grid <- recursive.mask.grid.surface.graph(mask.cross(3), level = 1)
Convenience helpers that recursively subdivide a tetrahedron into four
corner subtetrahedra according to a four-corner keep-mask, retain the
selected subtetrahedra at each recursion step, and deform the resulting
simplicial graph inside . This provides a generic
tetrahedral gasket family that includes the classic Sierpinski tetrahedron
together with corner-omission variants.
recursive.tetrahedron.mask.surface.graph( mask = mask.tetrahedron.classic(), level = 2, surface = c("standard", "squashed", "twisted", "wavy"), amplitude = 0.3, freq = 2, twist = 0.6, normalize = c("median", "mean", "none") )recursive.tetrahedron.mask.surface.graph( mask = mask.tetrahedron.classic(), level = 2, surface = c("standard", "squashed", "twisted", "wavy"), amplitude = 0.3, freq = 2, twist = 0.6, normalize = c("median", "mean", "none") )
mask |
Four-entry logical or numeric keep-mask. Non-zero entries are retained at each recursive step. |
level |
Recursion depth. May be |
surface |
Tetrahedron surface family. One of |
amplitude |
Finite deformation amplitude. |
freq |
Positive modulation frequency used only when
|
twist |
Finite twist strength used only when
|
normalize |
Normalization applied to the induced edge lengths. One of
|
The mask entries are interpreted in the order
base_left, base_right, base_back, and apex.
Named masks are reordered automatically to match that convention.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
recursive.tetrahedron.mask.surface.graph() returns a list with
components:
edges: the retained recursive tetrahedron-mask edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the canonical 3D tetrahedron coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "recursive.tetrahedron.mask",
surface: the chosen surface name,
level: the recursion depth,
mask: the logical keep-mask,
label: a human-readable family label.
tetrahedron <- recursive.tetrahedron.mask.surface.graph(level = 1)tetrahedron <- recursive.tetrahedron.mask.surface.graph(level = 1)
Convenience helpers that recursively subdivide an equilateral triangle into
three corner subtriangles plus one central inverted subtriangle according to
a four-slot keep-mask, retain the selected subtriangles at each recursion
step, and lift the resulting vertex graph into . This
provides a generic gasket-style triangular family that includes the classic
Sierpinski triangle together with bridge and asymmetric variants.
recursive.triangle.mask.surface.graph( mask = mask.triangle.classic(), level = 2, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )recursive.triangle.mask.surface.graph( mask = mask.triangle.classic(), level = 2, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )
mask |
Four-entry logical or numeric keep-mask. Non-zero entries are retained at each recursive step. |
level |
Recursion depth. May be |
surface |
Triangle surface family. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the first canonical triangle
coordinate. Used only when |
freq.v |
Positive ripple frequency in the second canonical triangle
coordinate. Used only when |
x.scale |
Positive horizontal scaling applied to the canonical triangle coordinates. |
y.scale |
Positive vertical scaling applied to the canonical triangle coordinates. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The mask entries are interpreted in the order
left, right, top, and center. Named masks are
reordered automatically to match that convention.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
recursive.triangle.mask.surface.graph() returns a list with
components:
edges: the retained recursive triangle-mask edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the canonical 2D triangle coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "recursive.triangle.mask",
surface: the chosen surface name,
level: the recursion depth,
mask: the logical keep-mask,
label: a human-readable family label.
triangle <- recursive.triangle.mask.surface.graph(level = 1)triangle <- recursive.triangle.mask.surface.graph(level = 1)
repulsive.stage() performs a gradient-descent stage for the
pure repulsion objective evaluated by repulsive.state(). It is intended
for GMDS experiments that need to inspect repulsion separately from
edge-length repair.
repulsive.stage( coords, lambda = 1, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, max.iter = 80L, initial.step = 0.02, step.shrink = 0.5, armijo = 1e-04, min.step = 1e-08, grad.tol = 1e-07, recenter = TRUE, distance.eps = 1e-10, return.frames = FALSE, engine = c("cpp", "R") )repulsive.stage( coords, lambda = 1, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, max.iter = 80L, initial.step = 0.02, step.shrink = 0.5, armijo = 1e-04, min.step = 1e-08, grad.tol = 1e-07, recenter = TRUE, distance.eps = 1e-10, return.frames = FALSE, engine = c("cpp", "R") )
coords |
Numeric |
lambda |
Repulsion strength. The returned total energy is
|
pair.index |
Optional two-column matrix of 1-based vertex pairs. If
|
pair.weights |
Optional non-negative pair weights parallel to
|
repulsion.family |
Repulsion potential family, either |
repulsion.delta |
Small positive softening parameter for pair distances. |
repulsion.power |
Power used by the |
max.iter |
Maximum number of gradient-descent iterations. |
initial.step |
Initial gradient step size. |
step.shrink |
Multiplicative shrink factor used by backtracking. |
armijo |
Armijo sufficient-decrease coefficient. |
min.step |
Minimum allowable step before the stage stops. |
grad.tol |
Gradient-norm stopping tolerance. |
recenter |
Logical; whether to recenter coordinates after each proposal. |
distance.eps |
Small positive distance floor used in derivatives. |
return.frames |
Logical; whether to return accepted coordinate frames. Frame 0 is the starting coordinate matrix and later frames are accepted updates. |
engine |
Backend engine. |
A list with coords, final state, a data-frame trace, and,
when requested, a list of coordinate frames.
theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) fit <- repulsive.stage( initial, lambda = 0.1, max.iter = 1, engine = "R" )theta <- seq(0, 2 * pi, length.out = 7)[-7] initial <- cbind(cos(theta), sin(theta)) fit <- repulsive.stage( initial, lambda = 0.1, max.iter = 1, engine = "R" )
repulsive.state() evaluates only the repulsion term used by the
experimental GMDS repulsive-unfolding operators. Unlike
edge.repulsive.state(), this function has no graph-edge term and does
not require placeholder edges or edge lengths.
repulsive.state( coords, lambda = 1, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, distance.eps = 1e-10, engine = c("cpp", "R") )repulsive.state( coords, lambda = 1, pair.index = NULL, pair.weights = NULL, repulsion.family = c("log", "inverse_power"), repulsion.delta = 0.001, repulsion.power = 1, distance.eps = 1e-10, engine = c("cpp", "R") )
coords |
Numeric |
lambda |
Repulsion strength. The returned total energy is
|
pair.index |
Optional two-column matrix of 1-based vertex pairs. If
|
pair.weights |
Optional non-negative pair weights parallel to
|
repulsion.family |
Repulsion potential family, either |
repulsion.delta |
Small positive softening parameter for pair distances. |
repulsion.power |
Power used by the |
distance.eps |
Small positive distance floor used in derivatives. |
engine |
Backend engine. |
A list containing energy, unscaled repulsion energy, gradient, gradient norm, and embedded pair lengths.
theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) state <- repulsive.state(coords, lambda = 0.1, engine = "R")theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) state <- repulsive.state(coords, lambda = 0.1, engine = "R")
gripui Shiny applicationRun the gripui Shiny application
run.gripui( project, host = "127.0.0.1", port = getOption("shiny.port"), launch.browser = interactive(), auto.stop.after = NULL, ... )run.gripui( project, host = "127.0.0.1", port = getOption("shiny.port"), launch.browser = interactive(), auto.stop.after = NULL, ... )
project |
A |
host |
Host passed to |
port |
Port passed to |
launch.browser |
Whether to launch a browser. |
auto.stop.after |
Optional delay, in seconds, after which the app stops itself. This is mainly useful for automated examples and tests. |
... |
Additional arguments passed to |
Invisibly returns the result of shiny::runApp().
graph <- list(adj_list = list(2L, c(1L, 3L), 2L)) layouts <- data.frame( candidate = "toy.layout", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = graph, layouts = layouts, title = "Toy project") run.gripui( project, launch.browser = FALSE, quiet = TRUE, auto.stop.after = 0.1 )graph <- list(adj_list = list(2L, c(1L, 3L), 2L)) layouts <- data.frame( candidate = "toy.layout", stage = "layout", seed = 1L, status = "ok", stringsAsFactors = FALSE ) project <- gripui.project(graph = graph, layouts = layouts, title = "Toy project") run.gripui( project, launch.browser = FALSE, quiet = TRUE, auto.stop.after = 0.1 )
Run the graph-family geometry explorer Shiny application
run.gripui.family( catalog = gripui.graph.family.catalog(), title = "Graph Family Geometry Explorer", subtitle = "Interactive geometry browser for synthetic benchmark families.", host = "127.0.0.1", port = getOption("shiny.port"), launch.browser = interactive(), auto.stop.after = NULL, ... )run.gripui.family( catalog = gripui.graph.family.catalog(), title = "Graph Family Geometry Explorer", subtitle = "Interactive geometry browser for synthetic benchmark families.", host = "127.0.0.1", port = getOption("shiny.port"), launch.browser = interactive(), auto.stop.after = NULL, ... )
catalog |
Family catalog, usually |
title |
Application title. |
subtitle |
Optional subtitle shown in the sidebar. |
host |
Host passed to |
port |
Port passed to |
launch.browser |
Whether to launch a browser. |
auto.stop.after |
Optional delay, in seconds, after which the app stops itself. This is mainly useful for automated examples and tests. |
... |
Additional arguments passed to |
Invisibly returns the result of shiny::runApp().
run.gripui.family(launch.browser = FALSE, quiet = TRUE, auto.stop.after = 0.1)run.gripui.family(launch.browser = FALSE, quiet = TRUE, auto.stop.after = 0.1)
Convenience helpers that sample points uniformly from a user-specified
rectangle, lift the sampled planar coordinates into , and
then build exact intersection-kNN graphs on either the planar or embedded
coordinates. The lifted surface uses normalized rectangle coordinates for the
non-flat -displacement while preserving the original rectangle in the
returned and coordinates.
sampled.rectangle.surface.graph( n, k, xmin = -1, xmax = 1, ymin = -1, ymax = 1, seed = NULL, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, graph.space = c("surface", "param"), max.path.edge.ratio.deviation.thld = 0.1, path.edge.ratio.percentile = 0.5, threshold.percentile = 0, normalize = c("median", "mean", "none") ) sampled.rectangle.surface.graphs( n, k, xmin = -1, xmax = 1, ymin = -1, ymax = 1, seed = NULL, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, graph.space = c("surface", "param"), max.path.edge.ratio.deviation.thld = 0.1, path.edge.ratio.percentile = 0.5, threshold.percentile = 0, normalize = c("median", "mean", "none") )sampled.rectangle.surface.graph( n, k, xmin = -1, xmax = 1, ymin = -1, ymax = 1, seed = NULL, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, graph.space = c("surface", "param"), max.path.edge.ratio.deviation.thld = 0.1, path.edge.ratio.percentile = 0.5, threshold.percentile = 0, normalize = c("median", "mean", "none") ) sampled.rectangle.surface.graphs( n, k, xmin = -1, xmax = 1, ymin = -1, ymax = 1, seed = NULL, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, graph.space = c("surface", "param"), max.path.edge.ratio.deviation.thld = 0.1, path.edge.ratio.percentile = 0.5, threshold.percentile = 0, normalize = c("median", "mean", "none") )
n |
Number of sampled points. |
k |
Integer iKNN neighborhood size (single graph) or vector of neighborhood sizes (graph sequence). |
xmin |
Left rectangle boundary. |
xmax |
Right rectangle boundary. Must satisfy |
ymin |
Bottom rectangle boundary. |
ymax |
Top rectangle boundary. Must satisfy |
seed |
Optional integer seed used only for the rectangle sampling. |
surface |
Geometry family used for the 3D lift. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the horizontal rectangle
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical rectangle direction.
Used only when |
graph.space |
Coordinate system used to build the iKNN graph and its raw
edge weights. |
max.path.edge.ratio.deviation.thld |
Geometric-pruning deviation
threshold in |
path.edge.ratio.percentile |
Edge-length percentile in |
threshold.percentile |
Optional long-edge pruning percentile in
|
normalize |
Normalization applied to the final positive edge weights.
One of |
For the graph constructors, the iKNN relation determines which edges are present, while the returned edge lengths are taken from the 3D endpoint distances in the lifted embedding so that the graph metric reflects the chosen surface geometry.
The coords.param component contains the sampled planar coordinates.
The coords.surface component contains the corresponding 3D
embedding. sampled.rectangle.surface.graph() returns a single weighted
iKNN graph for one k value, while
sampled.rectangle.surface.graphs() reuses the same sample and embedding
across a sequence of k values.
The coords_param component is an n x 2 numeric
matrix with columns u and v.
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z.
sampled.rectangle.surface.graph() returns a list with components:
edges: the undirected iKNN edges,
n: number of vertices,
edge_weights: normalized positive 3D chord lengths on the
retained iKNN edges,
raw_edge_weights: the unnormalized 3D chord lengths before
normalize,
iknn_witness_edge_weights: raw iKNN witness weights based on
common-neighbor distances, retained for diagnostics,
coords_surface: the sampled 3D embedding,
coords_param: the sampled planar rectangle coordinates,
coords_param_unit: the centered unit-rectangle coordinates
used for the surface lift,
weight_scale: normalization constant applied to the raw edge
weights,
family: always "sampled.rectangle",
surface: the chosen surface name,
graph_space: the coordinate system used for iKNN graph
construction,
k: the iKNN neighborhood size,
label: a human-readable family label.
sampled.rectangle.surface.graphs() returns a list with components:
graphs: named list of single-k graph bundles,
k: integer vector of retained k values,
k_statistics: per-k edge-count summary,
coords_surface: the shared sampled 3D embedding,
coords_param: the shared sampled planar coordinates,
coords_param_unit: the centered unit-rectangle coordinates
used for the surface lift,
family: always "sampled.rectangle",
surface: the chosen surface name,
graph_space: the coordinate system used for iKNN graph
construction,
label: a human-readable family label.
rectangle <- sampled.rectangle.surface.graph(n = 20, k = 4, seed = 1) sequence <- sampled.rectangle.surface.graphs( n = 20, k = c(3, 4), seed = 1 )rectangle <- sampled.rectangle.surface.graph(n = 20, k = 4, seed = 1) sequence <- sampled.rectangle.surface.graphs( n = 20, k = c(3, 4), seed = 1 )
Measures recovery of known coordinates, not preservation of graph distances. Existing layout stability and Figure 7 diagnostics are not changed.
score.coordinates( coords, reference, alignment = c("rigid", "none", "similarity"), allow.reflection = TRUE )score.coordinates( coords, reference, alignment = c("rigid", "none", "similarity"), allow.reflection = TRUE )
coords, reference
|
Numeric matrices of identical dimensions, with rows in the same observation order. Row names do not trigger reordering. |
alignment |
One of |
allow.reflection |
Allow a reflection in the fitted orthogonal matrix. |
A rigid fit preserves all distances. A similarity fit removes uniform scale as well. No vertex correspondence is estimated. A collapsed source is allowed for rigid alignment but has no identifiable similarity scale and is rejected for similarity alignment. Nonunique rotations in rank-deficient configurations can have the same minimum error.
A list with rmse, relative_rmse, coords (aligned coordinates),
rotation, translation, scale, alignment, and reference_radius.
RMSE is the square root of the mean squared Euclidean vertex displacement,
not the mean over individual coordinate entries. Relative RMSE divides it
by the reference RMS radius about its centroid; it is NA for zero radius.
The transformation is scale * coords %*% rotation + translation.
x <- rbind(c(0, 0), c(1, 0), c(0, 1)) score.coordinates(x + 2, x)$rmse score.coordinates(2 * x, x, alignment = "similarity")$scalex <- rbind(c(0, 0), c(1, 0), c(0, 1)) score.coordinates(x + 2, x)$rmse score.coordinates(2 * x, x, alignment = "similarity")$scale
score.geodesic.kk() evaluates a layout using the full all-pairs
geodesic Kamada–Kawai objective. Distances are measured along fixed chosen
graph shortest paths, not by straight-line chord length.
score.geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, scale.mode = c("profiled", "user"), scale.L0 = NULL, return.pair.details = FALSE )score.geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, scale.mode = c("profiled", "user"), scale.L0 = NULL, return.pair.details = FALSE )
coords |
Numeric coordinate matrix with 2 or 3 columns. |
prepared |
Optional object returned by
|
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
stiffness |
Global stiffness constant \(K\). |
distance.floor |
Small positive floor used in
|
edge.length.epsilon |
Small positive stabilizer added inside each embedded edge length. |
scale.mode |
Either |
scale.L0 |
Optional user-supplied geodesic KK scale, required when
|
return.pair.details |
If |
By default the global target scale L0 is fit analytically for the
supplied layout. Alternatively, the score can be evaluated at a user-supplied
scale.
A one-row data frame with the fitted or user-supplied scale factor and full geodesic KK energy summary.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.geodesic.kk(cycle_edges, n = 6) score <- score.geodesic.kk(coords, prepared = prepared)cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.geodesic.kk(cycle_edges, n = 6) score <- score.geodesic.kk(coords, prepared = prepared)
score.gmds() provides a common diagnostic panel for GMDS-oriented
layouts. It summarizes edge-length fidelity, fixed-path geodesic
stress, short/mid/long geodesic bands, ordinary metric-MDS chord stress, and
simple spread/shortcut diagnostics for any coordinate matrix on a prepared
graph.
score.gmds( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, scale.mode = c("profiled", "identity", "user"), edge.scale = NULL, path.scale = NULL, chord.scale = NULL, distance.floor = 1e-08, edge.length.epsilon = 1e-08, band.quantiles = c(1/3, 2/3) )score.gmds( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, scale.mode = c("profiled", "identity", "user"), edge.scale = NULL, path.scale = NULL, chord.scale = NULL, distance.floor = 1e-08, edge.length.epsilon = 1e-08, band.quantiles = c(1/3, 2/3) )
coords |
Numeric coordinate matrix. |
prepared |
Optional object returned by |
edges |
Two-column integer edge matrix used when |
n |
Finite positive integer vertex count. When supplied with a prepared object, it must match the stored graph size. |
adj.list |
Optional adjacency list used when |
weight.list |
Optional edge-weight list parallel to |
edge.weights |
Optional positive edge weights parallel to |
scale.mode |
Scale policy for edge, path, and chord targets:
|
edge.scale, path.scale, chord.scale
|
Optional user scales used when
|
distance.floor |
Positive floor for relative residuals. |
edge.length.epsilon |
Small stabilizer for fixed-path embedded lengths. |
band.quantiles |
Two quantiles splitting graph distances into short, mid, and long bands. |
A one-row data frame. Lower residual errors indicate closer agreement with the stated targets; no single column certifies geometric recovery.
A chord is the straight-line distance between two coordinates. A retained path adds embedded edge lengths along a route stored in the preparation. These can disagree on a folded graph. The diagnostic targets use the stored route convention and can differ slightly from strict shortest distances near ties. Compare candidates with the same graph, preparation, and scale policy.
n.vertices, n.edges, n.pairs: graph size and numbers of stored edges
and retained pairs (before exclusion of invalid or near-zero targets).
scale.mode: the requested scale policy. edge.scale, gmds.scale, and
metric.chord.scale multiply edge, path, and chord targets separately.
edge.rel.rmse, gmds.stress, metric.chord.stress: root sum squared
residual divided by root sum squared scaled target, a dimensionless error.
This is not the mean of squared pairwise relative errors and is not the
raw stress minimized by metric.mds().
edge.rmse, gmds.rmse, metric.chord.rmse: root mean squared residual
in drawn-coordinate units against the scaled targets.
edge.mean.abs.error, gmds.mean.abs.error: mean absolute residual in
drawn-coordinate units. The corresponding mean.rel.abs.error columns
(also available for metric.chord) average absolute residual/target ratios.
edge.signed.bias, gmds.signed.bias: mean residual/target ratio;
positive values indicate lengths greater than their scaled targets.
gmds.short.stress, gmds.mid.stress, gmds.long.stress and their
signed.bias counterparts: the path statistics restricted to bands defined
by band.quantiles; ties at a boundary belong to the lower band.
shortcut.fraction: fraction of evaluated retained paths more than 5%
shorter than their scaled target, between zero and one.
spread.score: RMS chord length divided by RMS unscaled graph target;
it changes with drawing scale and is not a universal quality grade.
Residual summaries exclude nonfinite values, nonpositive weights, and targets
no larger than distance.floor. Unavailable summaries are NA, including
path/chord diagnostics for edge-only preparations. No reference alignment
is performed. Use score.coordinates() or score.surface() for reference
agreement, keeping their alignment and units explicit.
Start with vignette("function-guide", package = "grip")
to choose a layout, diagnostic, or reference comparison. List installed
guides with vignette(package = "grip").
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) score <- score.gmds(coords, prepared = prepared) score[, c("scale.mode", "edge.rel.rmse", "gmds.stress", "metric.chord.stress")] # These dimensionless errors assess edges, retained paths, and chords; # they do not measure agreement with reference coordinates.cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.graph.geodesic.mds(cycle_edges, n = 6) score <- score.gmds(coords, prepared = prepared) score[, c("scale.mode", "edge.rel.rmse", "gmds.stress", "metric.chord.stress")] # These dimensionless errors assess edges, retained paths, and chords; # they do not measure agreement with reference coordinates.
score.landmark.geodesic.kk() evaluates a layout using the
landmark geodesic KK objective described in
landmark\_geodesic\_kk\_spec\_2026-03-30.tex. Distances are measured
along fixed chosen graph shortest paths, not by straight-line chord length.
The target scale factor L0 is fit analytically for the supplied layout
so that rankings are not dominated by an arbitrary global drawing scale.
score.landmark.geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, local.nbrs = 20L, landmark.count = 8L, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, return.pair.details = FALSE )score.landmark.geodesic.kk( coords, prepared = NULL, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, local.nbrs = 20L, landmark.count = 8L, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, return.pair.details = FALSE )
coords |
Numeric coordinate matrix with 2 or 3 columns. |
prepared |
Optional object returned by
|
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
local.nbrs |
Number of nearest graph-metric neighbors retained per
vertex when |
landmark.count |
Number of farthest-point landmarks retained per vertex
when |
stiffness |
Global stiffness constant \(K\). |
distance.floor |
Small positive floor used in
|
edge.length.epsilon |
Small positive stabilizer added inside each embedded edge length. |
return.pair.details |
If |
This is a scoring and comparison helper, not an optimizer.
A one-row data frame with the fitted scale factor and landmark geodesic KK energy summary.
cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.landmark.geodesic.kk( cycle_edges, n = 6, local.nbrs = 2, landmark.count = 2 ) score <- score.landmark.geodesic.kk(coords, prepared = prepared)cycle_edges <- edges.cycle(6) theta <- seq(0, 2 * pi, length.out = 7)[-7] coords <- cbind(cos(theta), sin(theta)) prepared <- prepare.landmark.geodesic.kk( cycle_edges, n = 6, local.nbrs = 2, landmark.count = 2 ) score <- score.landmark.geodesic.kk(coords, prepared = prepared)
score.layout() evaluates a realized layout without assuming a
canonical embedding. It is the low-level scoring helper behind
compare.layouts() and is most useful when you already have
one realized layout in hand, for example from a cached run or another graph
drawing tool. For real-world graphs, quality is judged by graph-distance
faithfulness, edge-length consistency, separation of non-neighbors, and
optionally edge crossings or cluster separation.
score.layout( coords, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, clusters = NULL, sample.size.stress = 2000L, sample.size.nonedge = 5000L, stress.seed = 1L, nonedge.seed = 1L, edge.crossings = c("auto", "always", "never"), edge.crossings.max.edges = 1000L )score.layout( coords, edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, clusters = NULL, sample.size.stress = 2000L, sample.size.nonedge = 5000L, stress.seed = 1L, nonedge.seed = 1L, edge.crossings = c("auto", "always", "never"), edge.crossings.max.edges = 1000L )
coords |
Numeric coordinate matrix with 2 or 3 columns. |
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. If omitted with |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Optional parallel list of positive edge weights. |
edge.weights |
Optional positive edge-weight vector parallel to
|
clusters |
Optional cluster or community labels of length
|
sample.size.stress |
Number of vertex pairs sampled for
|
sample.size.nonedge |
Number of non-edge pairs sampled for
|
stress.seed |
RNG seed used for the stress sample. |
nonedge.seed |
RNG seed used for the non-edge sample. |
edge.crossings |
How to compute |
edge.crossings.max.edges |
Edge-count threshold used by
|
The sampled stress is scale invariant. For sampled pairs , let
be graph distance and be Euclidean layout distance. The
fitted scale is , and the reported
value is . Edge-length CV is
the standard deviation divided by the mean of embedded edge lengths. The
sampled non-edge separation ratio is the minimum sampled non-edge distance
divided by the median embedded edge length. Cluster separation is the mean
pairwise distance between group centroids divided by the mean within-group
radius.
A one-row data frame with dot-delimited metric names.
Start with vignette("function-guide", package = "grip")
to choose a layout, diagnostic, or reference comparison. List installed
guides with vignette(package = "grip").
edges <- edges.mesh(5, 5) coords <- grip(edges, n = 25, dim = 2, preset = "mesh", seed = 1) score.layout(coords, edges = edges, n = 25)edges <- edges.mesh(5, 5) coords <- grip(edges, n = 25, dim = 2, preset = "mesh", seed = 1) score.layout(coords, edges = edges, n = 25)
score.misf.geodesic.kk() summarizes external coordinates against a
MISF-GKK prepared object using either the exact full geodesic-KK scorer or
the sparse landmark geodesic-KK scorer, depending on score.pair.mode. When
a full MISF-GKK fit is supplied, the function also carries over the
multiscale stage metadata and any trace tables retained by the optimizer.
score.misf.geodesic.kk( fit = NULL, coords = NULL, prepared = NULL, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, score.pair.mode = c("full", "landmark", "auto"), score.full.limit = 2048L, score.local.nbrs = 20L, score.landmark.count = 8L, return.trace = FALSE )score.misf.geodesic.kk( fit = NULL, coords = NULL, prepared = NULL, stiffness = 1, distance.floor = 1e-08, edge.length.epsilon = 1e-08, score.pair.mode = c("full", "landmark", "auto"), score.full.limit = 2048L, score.local.nbrs = 20L, score.landmark.count = 8L, return.trace = FALSE )
fit |
Optional fit from |
coords |
Optional coordinate matrix used when |
prepared |
Optional MISF-GKK prepared object used when |
stiffness |
Global stiffness constant \(K\). |
distance.floor |
Small positive floor used in
|
edge.length.epsilon |
Small positive stabilizer added inside each embedded edge length. |
score.pair.mode |
Requested scoring pair policy: |
score.full.limit |
Active-set size threshold used when
|
score.local.nbrs |
Sparse local-neighborhood size used for landmark-based scoring. |
score.landmark.count |
Sparse landmark count used for landmark-based scoring. |
return.trace |
If |
A one-row data frame with final MISF-GKK summary fields and either
full-GKK or landmark-GKK score columns, depending on the resolved scoring
policy. If return.trace = TRUE, trace list-columns are attached when
available.
mesh_edges <- edges.mesh(4, 4) prepared <- prepare.misf.geodesic.kk( mesh_edges, n = 16, num.init = 4, top.level.mode = "skip", seed = 1 ) coords <- matrix(seq_len(32), nrow = 16, ncol = 2) score <- score.misf.geodesic.kk(coords = coords, prepared = prepared)mesh_edges <- edges.mesh(4, 4) prepared <- prepare.misf.geodesic.kk( mesh_edges, n = 16, num.init = 4, top.level.mode = "skip", seed = 1 ) coords <- matrix(seq_len(32), nrow = 16, ncol = 2) score <- score.misf.geodesic.kk(coords = coords, prepared = prepared)
Compares already aligned surfaces using closest points on triangles, not nearest vertices. No registration, rescaling, or triangulation is performed.
score.surface( coords, triangles, reference.coords, reference.triangles, sample.size = 5000L, seed = 1L )score.surface( coords, triangles, reference.coords, reference.triangles, sample.size = 5000L, seed = 1L )
coords, reference.coords
|
Numeric three-column vertex matrices. |
triangles, reference.triangles
|
Three-column matrices of one-based triangle indices into the corresponding vertex matrix. Open surfaces and different triangulations are supported. Duplicate faces are rejected. |
sample.size |
Number of independent area-uniform samples per surface, at least two. Increase this to assess Monte Carlo convergence. |
seed |
Nonnegative integer seed, at most 2147483646. Separate fixed streams are used for the two directions; the caller's RNG state is restored. |
For surfaces A and B, squared symmetric RMS is one half of the sum of the area-normalized integrals of squared closest-point distance in the two directions. Each direction has equal weight regardless of total area. The returned score has coordinate-distance units. The Monte Carlo standard error uses a delta-method approximation; it does not quantify mesh discretization error, alignment uncertainty, or between-cloud variability. Zero observed error gives a standard error of zero, not a proof of identity. Samples are uniform over triangle area, so overlapping faces count with multiplicity. Self-intersections are not repaired or detected. Zero-area faces have no sampling mass but remain distance targets. A surface with no positive-area faces is rejected. No Hausdorff maximum is estimated.
A list with rms, forward_rms, reverse_rms, forward_mean,
reverse_mean, rms_mc_se, surface areas, zero-area face counts,
sample_size, and seed. Forward means coords to reference.
x <- rbind(c(0, 0, 0), c(1, 0, 0), c(0, 1, 0)) f <- matrix(1:3, nrow = 1) score.surface(x, f, x, f, sample.size = 100)$rmsx <- rbind(c(0, 0, 0), c(1, 0, 0), c(0, 1, 0)) f <- matrix(1:3, nrow = 1) score.surface(x, f, x, f, sample.size = 100)$rms
Convenience wrappers around recursive.mask.grid.surface.*() using the
classic carpet mask with the center cell removed.
sierpinski.carpet.surface.graph( level = 2, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )sierpinski.carpet.surface.graph( level = 2, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )
level |
Recursion depth. Must be at least |
surface |
Surface family used for the lift. One of |
amplitude |
Finite numeric amplitude controlling the non-flat displacement. |
freq.u |
Positive ripple frequency in the horizontal parameter
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical parameter direction.
Used only when |
x.scale |
Positive horizontal scaling of the parameter domain. |
y.scale |
Positive vertical scaling of the parameter domain. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component contains the 3D coordinates of the
occupied cells in the same vertex order as edges.sierpinski.carpet().
sierpinski.carpet.surface.graph() returns a reusable weighted-graph bundle
for the named Sierpinski carpet family.
The coords_surface component is an n x 3 numeric
matrix with columns x, y, and z, where
n = 8^level.
sierpinski.carpet.surface.graph() returns the same components as
recursive.mask.grid.surface.graph(), with family set to
"sierpinski.carpet" and a family-specific class and label.
carpet <- sierpinski.carpet.surface.graph(level = 1)carpet <- sierpinski.carpet.surface.graph(level = 1)
Convenience wrappers around recursive.tetrahedron.mask.surface.*()
using the classic all-corner tetrahedron mask. These helpers are intended
for benchmark families where the topology is the standard simplicial
tetrahedral gasket but the intended metric comes from a squashed, twisted,
or spatially varying realization.
sierpinski.tetrahedron.surface.graph( level = 2, surface = c("standard", "squashed", "twisted", "wavy"), amplitude = 0.3, freq = 2, twist = 0.6, normalize = c("median", "mean", "none") )sierpinski.tetrahedron.surface.graph( level = 2, surface = c("standard", "squashed", "twisted", "wavy"), amplitude = 0.3, freq = 2, twist = 0.6, normalize = c("median", "mean", "none") )
level |
Recursion depth. May be |
surface |
Tetrahedron surface family. One of |
amplitude |
Finite deformation amplitude. |
freq |
Positive modulation frequency used only when
|
twist |
Finite twist strength used only when
|
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
sierpinski.tetrahedron.surface.graph() returns the same components as
recursive.tetrahedron.mask.surface.graph(), with family set to
"sierpinski.tetrahedron" and a family-specific class and label.
tetrahedron <- sierpinski.tetrahedron.surface.graph(level = 1)tetrahedron <- sierpinski.tetrahedron.surface.graph(level = 1)
Convenience helpers that take the canonical recursive embedding of the
Sierpinski triangle graph and lift it into . These helpers
are intended for benchmark families where the topology is the usual
triangular gasket but the intended metric comes from a curved or folded
geometry rather than the flat equilateral reference drawing.
sierpinski.triangle.surface.graph( level = 2, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )sierpinski.triangle.surface.graph( level = 2, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )
level |
Recursion depth. May be |
surface |
Triangle surface family. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the first canonical triangle
coordinate. Used only when |
freq.v |
Positive ripple frequency in the second canonical triangle
coordinate. Used only when |
x.scale |
Positive horizontal scaling applied to the canonical triangle coordinates. |
y.scale |
Positive vertical scaling applied to the canonical triangle coordinates. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
sierpinski.triangle.surface.graph() returns a list with components:
edges: the Sierpinski triangle edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the canonical 2D triangle coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "sierpinski.triangle",
surface: the chosen surface name,
level: the recursion depth,
label: a human-readable family label.
triangle <- sierpinski.triangle.surface.graph(level = 1)triangle <- sierpinski.triangle.surface.graph(level = 1)
Convenience helpers that embed the sampled sphere graph into
and use the induced Euclidean edge lengths as positive
graph weights. These helpers are intended for benchmark families where the
graph topology follows the current pole-plus-latitude-rings sphere graph but
the intended metric comes from a curved or spatially varying 3D realization.
sphere.surface.graph( h, w = h, surface = c("standard", "ellipsoid", "wavy"), radius = 1, amplitude = 0.2, freq.theta = 3, freq.lat = 2, twist = 0.25, normalize = c("median", "mean", "none") )sphere.surface.graph( h, w = h, surface = c("standard", "ellipsoid", "wavy"), radius = 1, amplitude = 0.2, freq.theta = 3, freq.lat = 2, twist = 0.25, normalize = c("median", "mean", "none") )
h |
Number of latitude levels including the poles. Must be at least
|
w |
Wrapped longitude count. Defaults to |
surface |
Sphere surface family. One of |
radius |
Positive baseline radius. |
amplitude |
Finite deformation amplitude. For |
freq.theta |
Positive longitudinal frequency used only when
|
freq.lat |
Positive latitudinal frequency used only when
|
twist |
Finite longitude twist applied smoothly by latitude. The twist vanishes at the poles. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component contains the 3D coordinates of the sampled
surface in the same vertex order as edges: north pole first,
then latitude rings from north to south, then the south pole.
sphere.surface.graph() returns a reusable weighted-graph bundle containing
the sphere edges, induced edge weights, the 3D surface coordinates, and a 2D
longitude-latitude parameterization.
The coords_surface component is an n x 3 numeric matrix
with columns x, y, and z, where
n = 2 + (h - 2) * w.
sphere.surface.graph() returns a list with components:
edges: the undirected sphere-graph edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the 2D longitude-latitude parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "sphere",
surface: the chosen surface name,
label: a human-readable family label.
sphere <- sphere.surface.graph(4, 6, surface = "ellipsoid")sphere <- sphere.surface.graph(4, 6, surface = "ellipsoid")
Load a real graph offline, or browse the frozen package catalogue. No network, Python, or external viewer is needed. The catalogue includes the curated comparison gallery and all six examples used by Zheng, Pawar and Goodman. Gallery membership and original-six membership are separate columns.
suitesparse.graph(name) suitesparse.graphs()suitesparse.graph(name) suitesparse.graphs()
name |
Full graph ID (for example '"HB/494_bus"') or a unique short name ('"494_bus"'). Names are case-sensitive. Component-derived IDs include the '__LCC_' suffix and never resolve as the original full graph. |
Square matrices use the union of off-diagonal numerical support with its transpose, after summing duplicates and removing numerical zeros. Rectangular matrices use distinct row and column vertices. Matrix signs, magnitudes and physical units are not traversal lengths: every edge has length one. Some full graphs are disconnected. Largest-component graphs are explicitly identified and retain their original vertex mapping.
The installed selection is fixed; changing viewer favorites does not change package data. See 'extdata/suitesparse/selection-30_sept_2026.json' and 'extdata/suitesparse/PROVENANCE.html' in the installed package.
'suitesparse.graphs()' returns a data frame with 'id', 'name', 'group', 'vertices', 'edges', 'conversion_type', 'components', 'original_vertices', 'retained_fraction', 'gallery', and 'original_six'.
'suitesparse.graph()' returns a list with 'n' (including isolated vertices), 'edges' (a two-column integer matrix of unique, lexicographically sorted, one-based undirected edges), 'edge_weights' (unit traversal lengths), 'vertex_data', and 'provenance'. Vertex data contain consecutive 'vertex', one-based 'source_index', 'label', 'source_partition' ('row' or 'column'), 'original_vertex' (one-based index before component extraction), and one-based 'component', 'vertex_id' (saved graph identity), and 'source_vertex_id' (identity before extraction). In bipartite graphs, source indices refer separately to matrix rows and columns. Les Miserables retains character names.
Provenance includes source and download URLs, source matrix headers with original credits, CC BY 4.0 licensing, SHA-256 checksums, conversion recipe, original graph identity, and component retention information. The original six also retain their earlier metadata under 'original_example'.
SuiteSparse Matrix Collection, https://sparse.tamu.edu/.
Davis, T. A. and Hu, Y. (2011). The University of Florida Sparse Matrix Collection. doi:10.1145/2049662.2049663.
Zheng, J. X., Pawar, S. and Goodman, D. F. M. (2018). Graph Drawing by Stochastic Gradient Descent. doi:10.1109/TVCG.2018.2859997.
catalogue <- suitesparse.graphs() head(catalogue) g <- suitesparse.graph("494_bus") identical(g, suitesparse.graph("HB/494_bus")) c(vertices = g$n, edges = nrow(g$edges)) head(suitesparse.graph("lesmis")$vertex_data)catalogue <- suitesparse.graphs() head(catalogue) g <- suitesparse.graph("494_bus") identical(g, suitesparse.graph("HB/494_bus")) c(vertices = g$n, edges = nrow(g$edges)) head(suitesparse.graph("lesmis")$vertex_data)
Convenience constructors for the four-corner tetrahedron masks used by
recursive.tetrahedron.mask.surface.graph(). The slots
correspond to the four corner subtetrahedra created by one barycentric
refinement of a tetrahedron.
mask.tetrahedron.classic() mask.tetrahedron.corner.missing( omit = c("apex", "base_left", "base_right", "base_back") )mask.tetrahedron.classic() mask.tetrahedron.corner.missing( omit = c("apex", "base_left", "base_right", "base_back") )
omit |
Which tetrahedron corner is omitted in
|
The returned mask entries are ordered and named as base_left,
base_right, base_back, and apex.
A named logical vector of length 4.
classic <- mask.tetrahedron.classic() missing_apex <- mask.tetrahedron.corner.missing("apex")classic <- mask.tetrahedron.classic() missing_apex <- mask.tetrahedron.corner.missing("apex")
Convenience helpers that embed a toroidal grid graph into
and use the induced Euclidean edge lengths as positive
graph weights. These helpers are intended for benchmark families where the
graph topology is toroidal but the intended metric comes from a curved or
spatially varying 3D realization.
torus.surface.graph( h, w = h, surface = c("standard", "pinched", "wavy"), major.radius = 2, minor.radius = 0.75, amplitude = 0.2, freq.major = 2, freq.minor = 1, twist = 0.25, normalize = c("median", "mean", "none") )torus.surface.graph( h, w = h, surface = c("standard", "pinched", "wavy"), major.radius = 2, minor.radius = 0.75, amplitude = 0.2, freq.major = 2, freq.minor = 1, twist = 0.25, normalize = c("median", "mean", "none") )
h |
Number of wrapped rows. Must be at least |
w |
Number of wrapped columns. Defaults to |
surface |
Torus surface family. One of |
major.radius |
Positive distance from the torus center to the center of the tube. |
minor.radius |
Positive baseline radius of the torus tube. The local
tube radius must remain strictly smaller than |
amplitude |
Finite numeric deformation amplitude. |
freq.major |
Positive angular frequency around the major cycle, used by
|
freq.minor |
Positive angular frequency around the minor cycle, used by
|
twist |
Finite phase twist applied periodically to the minor angle as a function of the major angle. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component contains the 3D coordinates of the embedded
toroidal grid. torus.surface.graph() returns a reusable weighted-graph
bundle containing the torus edges, induced edge weights, the 3D surface
coordinates, and a 2D unwrapped parameterization.
The coords_surface component is an n x 3 numeric matrix with
columns x, y, and z.
torus.surface.graph() returns a list with components:
edges: the undirected toroidal-grid edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D surface embedding,
coords_param: the 2D unwrapped parameter coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "torus",
surface: the chosen surface name,
label: a human-readable family label.
torus <- torus.surface.graph(4, 6, surface = "pinched")torus <- torus.surface.graph(4, 6, surface = "pinched")
This is the tracing counterpart to grip(). The
metric argument selects the hop-based or edge-length-based compiled
engine while the remaining trace and diagnostic options keep the same
meaning in both cases. See grip() for detailed edge-length
semantics.
trace.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, tinit.factor = 6, seed = 6, trace = c("round", "level"), trace.every = 1, diagnostics = c("none", "light", "full"), target.coords = NULL, diagnostic.sample.size.nonedge = 1000L, diagnostic.sample.size.stress = 500L, diagnostic.nonedge.seed = 1L, diagnostic.stress.seed = 1L, metric = c("hop", "edge_length"), metric.neighbor.cap = NULL, length.normalization = c("median", "mean", "none") )trace.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 160, final.rounds = 384, num.init = 24, num.nbrs = 20, r = 0.03, s = 7.5, repulsion.factor = 2.5, coarse.repulsion.factor = 1.5, coarse.repulsion.sample = 16, coarse.repulsion.exact.below = 64, final.anchor.factor = 0, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, lgkk.polish.rounds = 0L, lgkk.multiscale.rounds = 0L, lgkk.rounds.coarse = NULL, lgkk.rounds.pre.final = NULL, lgkk.rounds.final = NULL, lgkk.local.nbrs = 20L, lgkk.landmark.count = 8L, lgkk.multiscale.scope = c("all", "coarse"), lgkk.active.limit = 4096L, tinit.factor = 6, seed = 6, trace = c("round", "level"), trace.every = 1, diagnostics = c("none", "light", "full"), target.coords = NULL, diagnostic.sample.size.nonedge = 1000L, diagnostic.sample.size.stress = 500L, diagnostic.nonedge.seed = 1L, diagnostic.stress.seed = 1L, metric = c("hop", "edge_length"), metric.neighbor.cap = NULL, length.normalization = c("median", "mean", "none") )
edges |
Two-column integer matrix of edges (1-based vertex ids).
Supply either |
n |
Number of vertices, a finite positive integer. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Parallel list of edge lengths for |
edge.weights |
Vector of edge lengths for |
dim |
Layout dimension (2 or 3). Default is 3. |
placement |
Initial placement strategy. "circle" is only used for 2D. |
preset |
Optional tuning preset. |
rounds |
Initial rounds for refinement. |
final.rounds |
Final rounds for refinement. |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of graph-distance neighbors retained for local refinement at each filtration level. |
r |
Main local temperature adaptation rate in |
s |
Non-negative boost factor applied when successive displacements have a consistent direction. |
repulsion.factor |
Non-negative multiplier applied to GRIP's finest-level repulsive force scale. |
coarse.repulsion.factor |
Non-negative multiplier applied to the extra
coarse-level active-set repulsion term. |
coarse.repulsion.sample |
Positive integer sample size used to approximate active-set-wide repulsion on larger coarse levels. |
coarse.repulsion.exact.below |
Positive integer threshold. When the active set size is at most this value, the coarse repulsion is computed exactly against all currently active vertices instead of being sampled. |
final.anchor.factor |
Non-negative multiplier for an anchor term that
pulls the final FR stage back toward the pre-final full-graph layout.
|
final.move.scale.after.first |
Scalar in |
final.mode |
Final full-graph refinement mode. |
insertion.anchor.count |
Positive integer number of anchor vertices used
during multiscale insertion on non-initial MISF refinement levels. This is
the closest current implementation to a global |
insertion.anchor.scope |
Anchor-eligibility rule used during multiscale
insertion. |
insertion.anchor.strategy |
Anchor-selection rule used during
multiscale insertion. |
level0.insertion.mode |
Level-0 insertion placement override used only
when the finest filtration level is first populated. |
level0.anchor.count |
Positive integer number of already placed anchors
to collect for level-0 insertion experiments. By default this inherits
|
level0.local.kk.steps |
Non-negative integer number of tiny local KK micro-polish steps applied immediately after each level-0 insertion. The legacy behavior uses 3. |
lgkk.polish.rounds |
Non-negative integer number of experimental
landmark-geodesic KK polish iterations applied after the main GRIP solve.
|
lgkk.multiscale.rounds |
Non-negative integer number of compiled
landmark-geodesic KK refinement rounds applied inside the multiscale solver
after each eligible MISF level completes its standard GRIP rounds.
This legacy shared budget is used as a fallback when any of the more
specific per-stage budgets below are left |
lgkk.rounds.coarse |
Optional non-negative integer number of compiled
LGKK rounds applied on coarse MISF levels with |
lgkk.rounds.pre.final |
Optional non-negative integer number of compiled
LGKK rounds applied on the last coarse level just before the full graph is
opened ( |
lgkk.rounds.final |
Optional non-negative integer number of compiled
LGKK rounds applied after the full graph level completes its standard GRIP
rounds ( |
lgkk.local.nbrs |
Number of nearest graph-metric neighbors retained per vertex in the LGKK sparse local set when either LGKK stage is enabled. |
lgkk.landmark.count |
Number of farthest-point landmarks retained per vertex in the LGKK sparse long-range set when either LGKK stage is enabled. |
lgkk.multiscale.scope |
Scope for the compiled multiscale LGKK stage.
|
lgkk.active.limit |
Positive integer upper bound on the active-set size for compiled multiscale LGKK cache construction. Levels larger than this skip the multiscale LGKK stage. |
tinit.factor |
Initial temperature factor. |
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
trace |
Snapshot granularity. |
trace.every |
Positive integer thinning factor for recorded rounds or levels. Initial and final snapshots are always included. |
diagnostics |
Optional per-frame diagnostic mode. |
target.coords |
Optional numeric target coordinate matrix used to append
per-frame Procrustes RMSE diagnostics. It must have |
diagnostic.sample.size.nonedge |
Positive integer sample size used for
per-frame non-edge separation diagnostics when
|
diagnostic.sample.size.stress |
Positive integer sample size used for
per-frame sampled stress when |
diagnostic.nonedge.seed |
RNG seed base used for per-frame non-edge separation diagnostics. |
diagnostic.stress.seed |
RNG seed base used for per-frame sampled stress diagnostics. |
metric |
Graph metric traced by the multiscale engine:
|
metric.neighbor.cap |
Weighted-metric search limit used only when
|
length.normalization |
Global normalization applied only when
|
A list containing the final layout, recorded coordinate frames, frame metadata, trace settings, canonical stage data, and any requested diagnostics.
Start with vignette("function-guide", package = "grip")
to choose a layout, diagnostic, or reference comparison. List installed
guides with vignette(package = "grip").
edges <- cbind(1:5, 2:6) tr <- trace.grip( edges, n = 6, metric = "hop", dim = 2, rounds = 3, final.rounds = 2, num.init = 3, trace = "level", diagnostics = "light", seed = 1 ) tr$metaedges <- cbind(1:5, 2:6) tr <- trace.grip( edges, n = 6, metric = "hop", dim = 2, rounds = 3, final.rounds = 2, num.init = 3, trace = "level", diagnostics = "light", seed = 1 ) tr$meta
Compute a trace for the legacy GRIP layout
trace.legacy.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 20, final.rounds = 25, num.init = 36, num.nbrs = 10, r = 0.15, s = 3, repulsion.factor = 1, tinit.factor = 6, seed = 6, trace = c("round", "level"), trace.every = 1 )trace.legacy.grip( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, placement = c("barycenter", "circle"), preset = NULL, rounds = 20, final.rounds = 25, num.init = 36, num.nbrs = 10, r = 0.15, s = 3, repulsion.factor = 1, tinit.factor = 6, seed = 6, trace = c("round", "level"), trace.every = 1 )
edges |
Two-column integer matrix of edges (1-based vertex ids).
Supply either |
n |
Number of vertices, a finite positive integer. |
adj.list |
Adjacency list (1-based) for undirected graphs. |
weight.list |
Optional parallel list of edge weights (edge lengths). If NULL, all edges are treated as weight 1. All weights must be finite and strictly positive. |
edge.weights |
Optional vector of edge weights for |
dim |
Layout dimension (2 or 3). Default is 3. |
placement |
Initial placement strategy. "circle" is only used for 2D. |
preset |
Optional tuning preset. |
rounds |
Initial rounds for refinement. |
final.rounds |
Final rounds for refinement. |
num.init |
Number of initial vertices in the coarsest level. |
num.nbrs |
Maximum number of graph-distance neighbors retained for local refinement at each filtration level. |
r |
Main local temperature adaptation rate in |
s |
Non-negative boost factor applied when successive displacements have a consistent direction. |
repulsion.factor |
Non-negative multiplier applied to GRIP's
finest-level repulsive force scale. |
tinit.factor |
Initial temperature factor. |
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
trace |
Snapshot granularity. |
trace.every |
Positive integer thinning factor for recorded rounds or levels. Initial and final snapshots are always included. |
A list with final, frames, meta, trace,
and trace.every. final is the final coordinate matrix.
frames is a list of coordinate matrices with NA rows for
vertices that have not yet been introduced by GRIP. meta is a data
frame describing each frame with columns frame, phase,
level_index, misf_level, round_in_level, and
active_vertices.
edges <- cbind(1:5, 2:6) tr <- trace.legacy.grip(edges, n = 6, dim = 2, placement = "barycenter", rounds = 3, final.rounds = 2, num.init = 3, num.nbrs = 4, trace = "level", trace.every = 1, seed = 1) tr$metaedges <- cbind(1:5, 2:6) tr <- trace.legacy.grip(edges, n = 6, dim = 2, placement = "barycenter", rounds = 3, final.rounds = 2, num.init = 3, num.nbrs = 4, trace = "level", trace.every = 1, seed = 1) tr$meta
Convenience constructors for the four-slot triangle masks used by
recursive.triangle.mask.surface.graph(). The slots correspond
to the three corner subtriangles and the central inverted subtriangle created
by one barycentric refinement of an equilateral triangle.
mask.triangle.classic() mask.triangle.bridge(missing = c("top", "left", "right"))mask.triangle.classic() mask.triangle.bridge(missing = c("top", "left", "right"))
missing |
Which outer corner is omitted in
|
The returned mask entries are ordered and named as left,
right, top, and center.
A named logical vector of length 4.
classic <- mask.triangle.classic() bridge <- mask.triangle.bridge("top")classic <- mask.triangle.classic() bridge <- mask.triangle.bridge("top")
Convenience helpers that triangulate a planar annulus by clipping a regular triangular lattice to the region between two concentric circles. The resulting graph is a triangulated manifold with boundary and a single hole, making it a useful complement to the closed triangulated-polyhedron families.
triangulated.annulus.surface.graph( resolution = 12, outer.radius = 1, inner.radius = 0.45, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )triangulated.annulus.surface.graph( resolution = 12, outer.radius = 1, inner.radius = 0.45, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )
resolution |
Positive lattice-resolution control. Larger values produce finer triangulations. |
outer.radius |
Positive outer annulus radius. |
inner.radius |
Positive inner annulus radius. Must be strictly smaller
than |
surface |
Geometry family used for the 3D lift. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the first planar coordinate. Used
only when |
freq.v |
Positive ripple frequency in the second planar coordinate. Used
only when |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component is the 3D coordinates
of the clipped lattice vertices in the same vertex order as
edges. triangulated.annulus.surface.graph()
returns a reusable weighted-graph bundle with the annulus edges, induced edge
weights, the 3D embedding, and the 2D annulus parameter coordinates.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
triangulated.annulus.surface.graph() returns a list with components:
edges: the triangulated-annulus edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the canonical 2D annulus coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "triangulated.annulus",
surface: the chosen surface name,
resolution: the lattice-resolution parameter,
label: a human-readable family label.
annulus <- triangulated.annulus.surface.graph(resolution = 6)annulus <- triangulated.annulus.surface.graph(resolution = 6)
Convenience helpers that triangulate a planar pair-of-pants domain by clipping a regular triangular lattice to a disk with two interior circular holes. The resulting graph is a triangulated surface with three boundary components and a deterministic non-grid topology.
triangulated.pair.of.pants.surface.graph( resolution = 12, outer.radius = 1.1, hole.radius = 0.24, hole.offset = 0.38, hole.height = 0.18, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )triangulated.pair.of.pants.surface.graph( resolution = 12, outer.radius = 1.1, hole.radius = 0.24, hole.offset = 0.38, hole.height = 0.18, surface = c("flat", "saddle", "paraboloid", "ripple", "folded"), amplitude = 0.6, freq.u = 1, freq.v = 1, normalize = c("median", "mean", "none") )
resolution |
Positive lattice-resolution control. Larger values produce finer triangulations. |
outer.radius |
Positive radius of the outer boundary. |
hole.radius |
Positive radius of each interior hole. |
hole.offset |
Positive horizontal offset of the two hole centers from the vertical axis. |
hole.height |
Vertical coordinate shared by the two hole centers. |
surface |
Geometry family used for the 3D lift. One of |
amplitude |
Finite deformation amplitude. |
freq.u |
Positive ripple frequency in the first planar coordinate. Used
only when |
freq.v |
Positive ripple frequency in the second planar coordinate. Used
only when |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component is the 3D
coordinates of the clipped lattice vertices in the same vertex order as
edges.
triangulated.pair.of.pants.surface.graph() returns a reusable
weighted-graph bundle with the pair-of-pants edges, induced edge weights, 3D
embedding, and the 2D parameter coordinates of the clipped domain.
The coords_surface component is an n x
3 numeric matrix with columns x, y, and z.
triangulated.pair.of.pants.surface.graph() returns a list with
components:
edges: the triangulated pair-of-pants edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the canonical 2D pair-of-pants coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "triangulated.pair.of.pants",
surface: the chosen surface name,
resolution: the lattice-resolution parameter,
label: a human-readable family label.
pair_of_pants <- triangulated.pair.of.pants.surface.graph(resolution = 8)pair_of_pants <- triangulated.pair.of.pants.surface.graph(resolution = 8)
Convenience helpers that take a triangular-face polyhedron, repeatedly split
each face into four subtriangles, merge shared-edge vertices, and use the
resulting triangulated-surface graph as a reusable benchmark family. The
canonical geometry is a piecewise-flat triangulated surface, while the
weighted variants can inflate, twist, or radially modulate that surface in
.
triangulated.polyhedron.surface.graph( base = c("tetrahedron", "octahedron", "icosahedron"), level = 1, surface = c("standard", "inflated", "twisted", "wavy"), amplitude = 0.25, freq = 2, twist = 0.6, normalize = c("median", "mean", "none") )triangulated.polyhedron.surface.graph( base = c("tetrahedron", "octahedron", "icosahedron"), level = 1, surface = c("standard", "inflated", "twisted", "wavy"), amplitude = 0.25, freq = 2, twist = 0.6, normalize = c("median", "mean", "none") )
base |
Base polyhedron. One of |
level |
Subdivision depth. |
surface |
Geometry family used for the 3D embedding. One of
|
amplitude |
Finite deformation amplitude. |
freq |
Positive modulation frequency used only when
|
twist |
Finite twist strength used only when
|
normalize |
Normalization applied to the induced edge lengths. One of
|
The current supported bases are the regular tetrahedron, octahedron, and icosahedron. These give closed triangulated surfaces with non-grid topology and a small number of extraordinary vertices, making them useful complements to the mesh-derived families already in the package.
The coords_surface component is an n x 3
numeric matrix with columns x, y, and z.
triangulated.polyhedron.surface.graph() returns a list with
components:
edges: the triangulated-surface edges,
n: number of vertices,
edge_weights: induced positive edge lengths,
coords_surface: the 3D embedding,
coords_param: the canonical piecewise-flat coordinates,
weight_scale: the normalization constant applied to the raw
edge lengths,
family: always "triangulated.polyhedron",
base: the chosen base polyhedron,
surface: the chosen surface name,
level: the subdivision depth,
subdivision: the linear face subdivision factor
2^level,
label: a human-readable family label.
tetrahedron <- triangulated.polyhedron.surface.graph( base = "tetrahedron", level = 1 )tetrahedron <- triangulated.polyhedron.surface.graph( base = "tetrahedron", level = 1 )
Convenience wrappers around recursive.mask.grid.surface.*() using the
connected axial-cross mask: center plus the four cardinal
neighbors. This produces a mesh-derived fractal family with strong
bottlenecks while remaining orthogonally connected at every level.
vicsek.surface.graph( level = 2, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )vicsek.surface.graph( level = 2, surface = c("saddle", "paraboloid", "ripple"), amplitude = 0.75, freq.u = 1, freq.v = 1, x.scale = 1, y.scale = 1, normalize = c("median", "mean", "none") )
level |
Recursion depth. Must be at least |
surface |
Surface family used for the lift. One of |
amplitude |
Finite numeric amplitude controlling the non-flat displacement. |
freq.u |
Positive ripple frequency in the horizontal parameter
direction. Used only when |
freq.v |
Positive ripple frequency in the vertical parameter direction.
Used only when |
x.scale |
Positive horizontal scaling of the parameter domain. |
y.scale |
Positive vertical scaling of the parameter domain. |
normalize |
Normalization applied to the induced edge lengths. One of
|
The coords.surface component contains the 3D coordinates of the occupied
cells in the same vertex order as edges.
vicsek.surface.graph() returns a reusable weighted-graph bundle for the
named Vicsek family.
The coords_surface component is an n x 3 numeric matrix
with columns x, y, and z, where n = 5^level.
vicsek.surface.graph() returns the same components as
recursive.mask.grid.surface.graph(), with family set to
"vicsek" and a family-specific class and label.
vicsek <- vicsek.surface.graph(level = 1)vicsek <- vicsek.surface.graph(level = 1)
weighted.grip.nd() is an opt-in weighted GRIP layout backend
for embeddings in dimensions dim >= 2. It is implemented beside the
legacy 2D/3D GRIP code path so that existing weighted-GRIP entry points and
their dimensionality checks are unchanged.
weighted.grip.nd( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, preset = NULL, placement = c("barycenter", "circle"), rounds = 160, final.rounds = 256, num.init = NULL, num.nbrs = 24, r = 0.03, s = 6, repulsion.factor = 1.5, tinit.factor = 2, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), metric.neighbor.cap = NULL, insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, length.normalization = c("median", "mean", "none"), disconnected = c("components", "error"), seed = 6 )weighted.grip.nd( edges = NULL, n = NULL, adj.list = NULL, weight.list = NULL, edge.weights = NULL, dim = 3, preset = NULL, placement = c("barycenter", "circle"), rounds = 160, final.rounds = 256, num.init = NULL, num.nbrs = 24, r = 0.03, s = 6, repulsion.factor = 1.5, tinit.factor = 2, final.move.scale.after.first = 1, final.mode = c("fr", "kk_repulse"), metric.neighbor.cap = NULL, insertion.anchor.count = 3, insertion.anchor.scope = c("any_higher", "prev_misf"), insertion.anchor.strategy = c("first", "distance_band", "balanced_band", "spread_prev"), level0.insertion.mode = c("inherit", "barycenter", "least_squares"), level0.anchor.count = insertion.anchor.count, level0.local.kk.steps = 3, length.normalization = c("median", "mean", "none"), disconnected = c("components", "error"), seed = 6 )
edges |
Two-column integer matrix of edges (1-based vertex ids). |
n |
Number of vertices. |
adj.list |
Adjacency list (1-based) for an undirected graph. |
weight.list |
Parallel list of strictly positive edge lengths. |
edge.weights |
Optional vector of edge lengths for |
dim |
Embedding dimension. Must be at least 2. |
preset |
Optional weighted layout preset: |
placement |
Initial insertion placement strategy. |
rounds |
Number of weighted refinement rounds before the final phase. |
final.rounds |
Number of final weighted refinement rounds. |
num.init |
Coarsest-level size control. Defaults to at least
|
num.nbrs |
Local-neighborhood control used by the ND backend. |
r |
Movement-rate parameter in |
s |
Repulsion scale parameter. |
repulsion.factor |
Non-edge repulsion multiplier. |
tinit.factor |
Initial spread multiplier. |
final.move.scale.after.first |
Final-stage FR displacement multiplier
applied after the first final round. Must be in |
final.mode |
Final refinement mode: |
metric.neighbor.cap |
Optional cap on the number of settled Dijkstra
vertices used when building weighted neighborhood caches for inserted
vertices. |
insertion.anchor.count |
Number of already placed anchor vertices used when inserting non-final MISF levels. |
insertion.anchor.scope |
Anchor eligibility rule:
|
insertion.anchor.strategy |
Anchor selection rule:
|
level0.insertion.mode |
Level-0 insertion placement override:
|
level0.anchor.count |
Number of anchors used during level-0 insertion. |
level0.local.kk.steps |
Number of local weighted-KK polish steps used immediately after level-0 insertion. |
length.normalization |
Global edge-length normalization:
|
disconnected |
How to handle disconnected graphs:
|
seed |
Optional RNG seed for reproducibility. If NULL, uses current time. |
Numeric matrix with one row per vertex and dim columns.
cycle_edges <- edges.cycle(6) cycle_lengths <- seq(0.8, 1.3, length.out = nrow(cycle_edges)) layout <- weighted.grip.nd( edges = cycle_edges, n = 6, edge.weights = cycle_lengths, dim = 4, rounds = 1, final.rounds = 1, num.init = 5, num.nbrs = 2, seed = 1 )cycle_edges <- edges.cycle(6) cycle_lengths <- seq(0.8, 1.3, length.out = nrow(cycle_edges)) layout <- weighted.grip.nd( edges = cycle_edges, n = 6, edge.weights = cycle_lengths, dim = 4, rounds = 1, final.rounds = 1, num.init = 5, num.nbrs = 2, seed = 1 )