---
title: "Graph gallery: multiscale GRIP"
output:
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Graph gallery: multiscale GRIP}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

This gallery demonstrates multiscale GRIP on six graph families. For the
recommended embedding workflow, see [the SGD metric-MDS gallery](gallery.html).


This gallery complements the
[function guide](function-guide.html) and
[synthetic graph examples](synthetic-graph-families.html).

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  dev = "jpeg",
  dev.args = list(quality = 90),
  fig.retina = 1,
  dpi = 72,
  fig.width = 11,
  fig.height = 4.2
)
```

Installed figures use static projections. To enable 3D rotation and layout
selection, render with `options(grip.vignette.interactive = TRUE)` and
**ivue** and **rgl** installed.


This article is a guide to the synthetic graph families shipped with `grip`.
The package no longer provides only a few toy generators for smoke tests. It
now includes a broad collection of geometry-rich benchmark families covering:

- lifted lattices,
- recursive and fractal families,
- irregular manifolds,
- porous 3D families,
- and intrinsically weighted trees.

For many of these families, the package stores both:

- a target geometry used to induce edge lengths, and
- a weighted graph bundle that can be passed directly to
  `grip(metric = "edge_length")`.

As a workflow guide, use `grip()` on the purely topological versions of
these families when you want an unweighted baseline, and use
`grip(metric = "edge_length")` on the weighted bundles when the induced geometry is
part of the problem. Advanced GKK/LGKK scoring can be layered onto smaller
weighted examples later, but that is not the main purpose of this article.

```{r}
library(grip)
```

```{r view-helpers, include=FALSE}
source(system.file('scripts','vignette-views.R',package='grip'),local=TRUE)
```

The optional interactive views rotate and zoom. Reference and fitted coordinates are displayed
without rotation or scale fitting. The original 2D tree fit is preserved and
shown in the z = 0 plane of a 3D viewer.

## Family classes at a glance

The table below lists a representative subset of the larger family collection.

| Family class | Representative helper | Why it matters |
|:--|:--|:--|
| Lifted lattices | `mesh.surface.graph()` | Plain topology, nontrivial metric geometry |
| Wrapped surfaces | `torus.surface.graph()` | Closed periodic surface geometry |
| Recursive fractals | `vicsek.surface.graph()` | Self-similar bottlenecks and holes |
| Irregular manifolds | `irregular.annulus.surface.graph()` | Non-lattice surface geometry with boundary |
| Porous 3D families | `cube.channel.network.surface.graph()` | Volumetric geodesic detours |
| Intrinsic trees | `kary.tree.weighted.graph()` | Geometry from edge lengths rather than ambient space |

This article shows one representative example from each class. The interactive
family browser described in `Interactive Exploration with gripui` exposes a
much larger catalog.

## Lifted lattices

The simplest geometry-rich family keeps the graph topology of a rectangular
mesh but induces edge lengths from a curved embedding in `R^3`.

```{r mesh-family}
mesh.graph <- mesh.surface.graph(
  5, 5,
  surface = "saddle",
  amplitude = 0.8
)

mesh.coords <- grip(metric = "edge_length",
  mesh.graph$edges,
  n = mesh.graph$n,
  edge.weights = mesh.graph$edge_weights,
  dim = 3,
  preset = "mesh",
  seed = 1
)

mesh.summary <- data.frame(
  family = mesh.graph$family,
  surface = mesh.graph$surface,
  n = mesh.graph$n,
  m = nrow(mesh.graph$edges),
  weight_scale = mesh.graph$weight_scale
)

knitr::kable(mesh.summary, digits = 3)
```

```{r mesh-interactive}
documentation.view(list(`Weighted GRIP`=mesh.coords, `Reference geometry`=mesh.graph$coords_surface, `Parameter grid`=cbind(mesh.graph$coords_param,z=0)), edges=mesh.graph$edges,
  aligned=TRUE, description="Reference and fitted geometries are centered without rotation or scale fitting.")
```

The useful design pattern here is that the topology stays simple while the
metric geometry becomes nontrivial.

## Wrapped surfaces

Wrapped lattices extend the same idea to periodic topologies such as a torus.

```{r torus-family}
torus.graph <- torus.surface.graph(
  5, 6,
  surface = "pinched",
  minor.radius = 0.33,
  amplitude = 0.18,
  twist = 0.18
)

torus.coords <- grip(metric = "edge_length",
  torus.graph$edges,
  n = torus.graph$n,
  edge.weights = torus.graph$edge_weights,
  dim = 3,
  preset = "torus",
  seed = 2
)

knitr::kable(
  data.frame(
    family = torus.graph$family,
    surface = torus.graph$surface,
    n = torus.graph$n,
    m = nrow(torus.graph$edges)
  )
)
```

```{r torus-interactive}
documentation.view(list(`Weighted GRIP`=torus.coords, `Reference geometry`=torus.graph$coords_surface), edges=torus.graph$edges,
  aligned=TRUE, description="Reference and fitted geometries are centered without rotation or scale fitting.")
```

These wrapped families are especially useful when ordinary planar intuition is
misleading and a 3D layout is the natural target.

## Recursive and fractal families

The package now includes recursive square-mask families such as the Vicsek
fractal and Sierpinski carpet variants, all of which can be lifted into curved
surface geometries.

```{r vicsek-family}
vicsek.graph <- vicsek.surface.graph(
  level = 2,
  surface = "ripple",
  amplitude = 0.55
)

vicsek.coords <- grip(metric = "edge_length",
  vicsek.graph$edges,
  n = vicsek.graph$n,
  edge.weights = vicsek.graph$edge_weights,
  dim = 3,
  preset = "carpet",
  seed = 3
)
```

```{r vicsek-interactive}
documentation.view(list(`Weighted GRIP`=vicsek.coords, `Reference geometry`=vicsek.graph$coords_surface), edges=vicsek.graph$edges,
  aligned=TRUE, description="Reference and fitted geometries are centered without rotation or scale fitting.")
```

Recursive families are useful because they create holes, bottlenecks, and
multi-scale detours that are hard to capture with simpler lattices.

## Irregular manifolds

Not all surface families in `grip` are based on regular grids. The package also
includes irregular triangulated manifolds with boundary and closed irregular
surfaces.

```{r annulus-family}
annulus.graph <- irregular.annulus.surface.graph(
  rings = 5,
  outer.count = 24,
  inner.radius = 0.42,
  surface = "folded",
  amplitude = 0.2
)

annulus.coords <- grip(metric = "edge_length",
  annulus.graph$edges,
  n = annulus.graph$n,
  edge.weights = annulus.graph$edge_weights,
  dim = 3,
  preset = "irregular",
  seed = 4
)
```

```{r annulus-interactive}
documentation.view(list(`Weighted GRIP`=annulus.coords, `Reference geometry`=annulus.graph$coords_surface), edges=annulus.graph$edges,
  aligned=TRUE, description="Reference and fitted geometries are centered without rotation or scale fitting.")
```

These families are important because they reduce lattice bias and produce more
variable local geometry than mesh-like constructions.

## Porous 3D families

The cubical branch introduces graphs that are genuinely volumetric rather than
surface-like. Channel networks and related porous families create 3D geodesic
detours that are hard to flatten cleanly.

```{r cube-family}
cube.graph <- cube.channel.network.surface.graph(
  side = 5,
  level = 1,
  surface = "twisted",
  twist = 0.2
)

cube.coords <- grip(metric = "edge_length",
  cube.graph$edges,
  n = cube.graph$n,
  edge.weights = cube.graph$edge_weights,
  dim = 3,
  preset = "irregular",
  seed = 5
)

knitr::kable(
  data.frame(
    family = cube.graph$family,
    n = cube.graph$n,
    m = nrow(cube.graph$edges)
  )
)
```

```{r cube-interactive}
documentation.view(list(`Weighted GRIP`=cube.coords, `Reference geometry`=cube.graph$coords_surface), edges=cube.graph$edges,
  aligned=TRUE, description="Reference and fitted geometries are centered without rotation or scale fitting.")
```

This family class is especially useful for testing whether a method can
preserve large-scale volumetric structure without collapsing tunnels and
channels.

## Intrinsic weighted trees

Some family geometries are intrinsic rather than ambient. The weighted tree
helpers preserve the exact tree topology while assigning edge lengths directly
from branch-depth and branch-position rules.

```{r tree-family}
tree.graph <- kary.tree.weighted.graph(
  k = 2,
  depth = 4,
  depth.rule = "geometric",
  depth.decay = 0.82,
  branch.rule = "linear",
  branch.spread = 0.25
)

tree.coords <- grip(metric = "edge_length",
  tree.graph$edges,
  n = tree.graph$n,
  edge.weights = tree.graph$edge_weights,
  dim = 2,
  preset = "tree",
  seed = 6
)

knitr::kable(
  head(tree.graph$edge_table[, c(
    "parent",
    "child",
    "child_depth",
    "branch_index",
    "edge_weight"
  )]),
  digits = 3
)
```

```{r tree-interactive}
documentation.view(list(`Weighted GRIP (2D fit)`=cbind(tree.coords,z=0)), edges=tree.graph$edges,
  aligned=TRUE, description="Reference and fitted geometries are centered without rotation or scale fitting.")
```

These tree families are useful because they separate intrinsic weighted
geometry from any arbitrary 3D embedding choice.

## Why this family library matters

The family collection now serves three roles:

- it gives users concrete examples of what the package can represent,
- it supports regression testing and benchmark design,
- and it makes it possible to study layout behavior under controlled geometric
  variation rather than only on a handful of fixed toy graphs.

## Learn more

- `Getting Started with grip` introduces the main layout APIs.
- `Weighted Graph Layouts with grip` explains how to use these family bundles
  with the weighted sister API.
- `Interactive Exploration with gripui` shows how to browse the larger family
  registry through `run.gripui.family()`.
