| Title: | Lightweight Adjacency Lists |
|---|---|
| Description: | Provides an S3 class to represent graph adjacency lists using 'vctrs'. Allows for creation, subsetting, combining, and pretty printing of these lists. Adjacency lists can be easily converted to zero-indexed lists, which allows for easy passing of objects to low-level languages for processing. |
| Authors: | Christopher T. Kenny [aut, cre] (ORCID: <https://orcid.org/0000-0002-9386-6860>), Cory McCartan [aut] (ORCID: <https://orcid.org/0000-0002-6251-669X>) |
| Maintainer: | Christopher T. Kenny <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-05-19 05:54:47 UTC |
| Source: | https://github.com/alarm-redist/adj |
Create an adjacency list from a list of vectors of adjacent node identifiers.
adj( ..., ids = NULL, duplicates = c("warn", "error", "allow", "remove"), self_loops = c("warn", "error", "allow", "remove") ) as_adj(x) is_adj(x) adj_to_list(x, ids = NULL)adj( ..., ids = NULL, duplicates = c("warn", "error", "allow", "remove"), self_loops = c("warn", "error", "allow", "remove") ) as_adj(x) is_adj(x) adj_to_list(x, ids = NULL)
... |
Vectors or a single list of vectors. Vectors should be comprised
either of (1-indexed) indices of adjacent nodes, or of unique identifiers,
which must match to the provided |
ids |
A vector of unique node identifiers. Each provided vector in |
duplicates |
Controls handling of duplicate neighbors. The value
|
self_loops |
Controls handling of self-loops (nodes that are adjacent
to themselves). The value |
x |
An |
Equality for adj lists is evaluated elementwise. Two sets of neighbors are
considered equal if they contain the same neighbors, regardless of order.
The adj package is not focused on graph operations. The length() function
will return the number of nodes. To compute the number of edges in an
adjacency list a, use sum(lengths(a)), and divide by 2 for undirected
graphs.
An adj list
a1 = adj(list(c(2, 3), c(1, 3), c(1, 2))) a2 = adj(list(c(3, 2), c(3, 1), c(2, 1))) a1 == a2 adj(2:3, NULL, 4:5, integer(0), 1) adj(1, 2, 3, self_loops = "remove") adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "remove")a1 = adj(list(c(2, 3), c(1, 3), c(1, 2))) a2 = adj(list(c(3, 2), c(3, 1), c(2, 1))) a1 == a2 adj(2:3, NULL, 4:5, integer(0), 1) adj(1, 2, 3, self_loops = "remove") adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "remove")
Greedily finds a coloring of an adjacency list, optionally grouped by a provided vector.
adj_color(x, groups = NULL, colors = 0, method = c("dsatur", "greedy"))adj_color(x, groups = NULL, colors = 0, method = c("dsatur", "greedy"))
x |
An |
groups |
An optional vector specifying the group membership for each node
in |
colors |
Number of colors to use. If 0 (the default), uses as few colors as possible with this greedy algorithm. |
method |
Coloring method to use. |
An integer vector
Brélaz, Daniel (1979-04-01). "New methods to color the vertices of a graph". Communications of the ACM. 22 (4): 251–256.
a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") adj_color(a) adj_color(a, colors = 3) adj_color(a, groups = c("AD", "BC", "BC", "AD"))a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") adj_color(a) adj_color(a, colors = 3) adj_color(a, groups = c("AD", "BC", "BC", "AD"))
Add and subtract edges from an adjacency list
adj_add_edges(x, v1, v2, ids = NULL) adj_subtract_edges(x, v1, v2, ids = NULL)adj_add_edges(x, v1, v2, ids = NULL) adj_subtract_edges(x, v1, v2, ids = NULL)
x |
An |
v1 |
vector of vertex identifiers for the first vertex. Can be an
integer index or a value to look up in |
v2 |
vector of vertex identifiers for the second vertex. Can be an
integer index or a value to look up in |
ids |
A vector of unique node identifiers. Each provided vector in |
An adj list
a <- adj(c(2, 3), 1, 1) adj_add_edges(a, 2, 3) adj_subtract_edges(a, 1, 2)a <- adj(c(2, 3), 1, 1) adj_add_edges(a, 2, 3) adj_subtract_edges(a, 1, 2)
adj list from a set of spatial polygonsRequires that the geos package be installed.
adj_from_shp(shp)adj_from_shp(shp)
shp |
An object convertible to |
An adj list
shp <- c( "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))", "POLYGON ((0 1, 1 1, 1 2, 0 2, 0 1))", "POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0))", "POLYGON ((1 1, 2 1, 2 2, 1 2, 1 1))" ) adj_from_shp(shp)shp <- c( "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))", "POLYGON ((0 1, 1 1, 1 2, 0 2, 0 1))", "POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0))", "POLYGON ((1 1, 2 1, 2 2, 1 2, 1 1))" ) adj_from_shp(shp)
adj overrides the default [ and c() methods to allow for filtering,
reordering, and concatenating adjacency lists while ensuring that indices
remain internally consistent.
## S3 method for class 'adj' x[i, ...] ## S3 method for class 'adj' c(...)## S3 method for class 'adj' x[i, ...] ## S3 method for class 'adj' c(...)
x |
An adjacency list of class |
i |
Indexing vector |
... |
For |
When duplicate indices are present in the adjacency list, indexing is
performed by slicing the adjacency matrix, which is slower and requires
more memory. For large adjacency lists, slicing with duplicates will
error for this reason; set options(adj.max_matrix_slice = Inf) to allow it,
but be aware of the possible memory usage implications.
A reindexed adjacency list for [, and a concatenated adjacency list for c().
a <- adj(c(2, 3), c(1, 3), c(1, 2)) a[1:2] all(sample(a) == a) # any permutation yields the same graph a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "remove") c(a, a) # concatenates graphs with no connecting edgesa <- adj(c(2, 3), c(1, 3), c(1, 2)) a[1:2] all(sample(a) == a) # any permutation yields the same graph a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "remove") c(a, a) # concatenates graphs with no connecting edges
The Laplacian matrix of a graph is defined as L = D - A, where D is the
degree matrix (a diagonal matrix where D[i, i] is the degree of node i)
and A is the adjacency matrix.
adj_laplacian(x, sparse = TRUE)adj_laplacian(x, sparse = TRUE)
x |
An |
sparse |
Whether to return a sparse matrix (of class |
A matrix representing the Laplacian of the graph.
a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") L <- adj_laplacian(a, sparse = FALSE) L # count spanning trees (any minor of the Laplacian) det(L[-1, -1])a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") L <- adj_laplacian(a, sparse = FALSE) L # count spanning trees (any minor of the Laplacian) det(L[-1, -1])
Adjacency lists can be converted to adjacency matrices and vice versa without loss.
adj_from_matrix( x, duplicates = c("warn", "error", "allow", "remove"), self_loops = c("warn", "error", "allow", "remove") ) ## S3 method for class 'adj' as.matrix(x, sparse = FALSE, ...)adj_from_matrix( x, duplicates = c("warn", "error", "allow", "remove"), self_loops = c("warn", "error", "allow", "remove") ) ## S3 method for class 'adj' as.matrix(x, sparse = FALSE, ...)
x |
An adjacency list or matrix |
duplicates |
Controls handling of duplicate neighbors. The value
|
self_loops |
Controls handling of self-loops (nodes that are adjacent
to themselves). The value |
sparse |
If |
... |
Ignored. |
adj_from_matrix() returns an adj list; as.matrix() returns a matrix.
adj_from_matrix(1 - diag(3)) a = adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") mat = as.matrix(a) all(a == adj_from_matrix(mat, duplicates = "allow")) # TRUEadj_from_matrix(1 - diag(3)) a = adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") mat = as.matrix(a) all(a == adj_from_matrix(mat, duplicates = "allow")) # TRUE
Computes the quotient graph of a given adjacency list by a provided grouping vector. Nodes in the same groups are merged into single nodes in the quotient graph. The resulting multi-edges and self-loops are handled according to the specified parameters.
adj_quotient( x, groups, duplicates = c("remove", "allow", "error", "warn"), self_loops = c("remove", "allow", "error", "warn") ) adj_quotient_int( x, groups, n_groups, duplicates = c("remove", "allow", "error", "warn"), self_loops = c("remove", "allow", "error", "warn") )adj_quotient( x, groups, duplicates = c("remove", "allow", "error", "warn"), self_loops = c("remove", "allow", "error", "warn") ) adj_quotient_int( x, groups, n_groups, duplicates = c("remove", "allow", "error", "warn"), self_loops = c("remove", "allow", "error", "warn") )
x |
An |
groups |
A vector specifying the group membership for each node in |
duplicates |
Controls handling of duplicate neighbors. The value
|
self_loops |
Controls handling of self-loops (nodes that are adjacent
to themselves). The value |
n_groups |
Number of unique groups. |
A new adj list.
a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") # merge two islands (A and D) adj_quotient(a, c("AD", "B", "C", "AD")) adj_quotient_int(a, c(1L, 2L, 3L, 1L), n_groups = 3L, self_loops = "allow")a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") # merge two islands (A and D) adj_quotient(a, c("AD", "B", "C", "AD")) adj_quotient_int(a, c(1L, 2L, 3L, 1L), n_groups = 3L, self_loops = "allow")
Subtracts 1 from each index in the adjacency list and returns a bare list of integer vectors, suitable for providing to C/C++ code that uses zero-based indexing.
adj_zero_index(x)adj_zero_index(x)
x |
An adjacency list. |
A list of integer vectors with zero-based indices.
a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") adj_zero_index(a)a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") adj_zero_index(a)
Adjacency lists are printed as sets of indices for each node.
## S3 method for class 'adj' format(x, n = 3, ...) ## S3 method for class 'adj' print(x, n = 3, ...)## S3 method for class 'adj' format(x, n = 3, ...) ## S3 method for class 'adj' print(x, n = 3, ...)
x |
An |
n |
Maximum number of neighbors to show before truncating with an ellipsis. |
... |
Ignored. |
A character vector representing each entry in the adjacency list.
a = adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") format(a) print(a, n = 5)a = adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") format(a) print(a, n = 5)
A dataset encoding the adjacency structure of seven bridges in Königsberg, Prussia, as described by Leonhard Euler in 1736.
konigsbergkonigsberg
konigsbergA data frame with 4 rows and 4 columns:
The four land areas, A-D, as described by Euler. Area 'A' corresponds to the central island of Kneiphof.
A list column, where each entry is a character vector listing the areas directly connected by bridges to the area in that row.
The longitude of the area center, for plotting.
The latitude of the area center, for plotting.
Euler, Leonhard (1741). "Solutio problematis ad geometriam situs pertinentis". Commentarii Academiae Scientiarum Petropolitanae: 128–140.
Plots an adjacency list as a set of nodes and edges, with optional coordinate values for each node. Edge thickness is proportional to the number of edges between each pair of nodes. Self loops are represented with larger points.
## S3 method for class 'adj' plot(x, y = NULL, edges = NULL, nodes = TRUE, xlab = NA, ylab = NA, ...)## S3 method for class 'adj' plot(x, y = NULL, edges = NULL, nodes = TRUE, xlab = NA, ylab = NA, ...)
x |
An |
y |
Optional matrix of coordinates for each node. If |
edges |
Type of line to use when drawing edges. Passed to |
nodes |
If |
xlab, ylab
|
Labels for the x- and y-axes. |
... |
Additional arguments passed on to the initial |
NULL, invisibly.
plot(adj(2, c(1, 3), 2)) plot(adj(2, c(1, 2, 3), c(2, 2, 2), self_loops="allow", duplicates="allow")) a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") plot(a, konigsberg[c("x", "y")])plot(adj(2, c(1, 3), 2)) plot(adj(2, c(1, 2, 3), c(2, 2, 2), self_loops="allow", duplicates="allow")) a <- adj(konigsberg$bridge_to, ids = konigsberg$area, duplicates = "allow") plot(a, konigsberg[c("x", "y")])
Reverse the direction of edges in an adjacency list. For undirected graphs, this is a no-op.
## S3 method for class 'adj' t(x)## S3 method for class 'adj' t(x)
x |
An |
An adj list with edges reversed.
a <- adj(2, 3, 1) all(t(a) == adj(3, 1, 2))a <- adj(2, 3, 1) all(t(a) == adj(3, 1, 2))