Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 36 additions & 18 deletions R/iterators.R
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,22 @@ identical_graphs <- function(
.Call(Rx_igraph_identical_graphs, g1, g2, as.logical(attrs))
}

# Build the `names` attribute of a vertex/edge sequence lazily.
#
# `source` is the graph's full vertex/edge name vector (shared by reference
# across all sequences of the graph) and `idx` is a 1-based index into it.
# The result is an ALTREP string vector that only materializes the actual
# names when they are first accessed (printing, named indexing, `as_ids()`),
# so constructing a sequence stays cheap even when many of them are returned
# at once (e.g. `max_cliques()`). Subsetting it stays lazy too, via the
# class's `Extract_subset` method. Returns `NULL` when there is no source.
lazy_index_names <- function(source, idx) {
if (is.null(source)) {
return(NULL)
}
.Call(Rx_igraph_lazy_names, source, idx)
}

add_vses_graph_ref <- function(vses, graph) {
ref <- get_vs_ref(graph)
if (!is.null(ref)) {
Expand Down Expand Up @@ -290,7 +306,7 @@ V <- function(graph) {

res <- seq_len(vcount(graph))
if (is_named(graph)) {
names(res) <- vertex_attr(graph)$name
names(res) <- lazy_index_names(vertex_attr(graph)$name, res)
}
class(res) <- "igraph.vs"
res <- set_complete_iterator(res)
Expand All @@ -315,10 +331,11 @@ unsafe_create_vs <- function(graph, idx, verts = NULL) {
}
# `idx` are vertex IDs straight from C, and `verts` is the full `V(graph)`,
# so `verts[idx]` would just be `idx` again -- skip that copy and use the
# IDs directly as the payload. Names are subset from `verts`, and the graph
# reference is shared from `verts`. All attributes are set in one
# `attributes<-` call to avoid the per-object shallow copies that dominate
# when many sequences are built (e.g. `max_cliques()`).
# IDs directly as the payload. Names are taken lazily from `verts` (an
# ALTREP that composes in O(1) under subsetting), and the graph reference is
# shared from `verts`. All attributes are set in one `attributes<-` call to
# avoid the per-object shallow copies that dominate when many sequences are
# built (e.g. `max_cliques()`).
vertex_names <- attr(verts, "names")
res <- as.integer(idx)
Comment thread
schochastics marked this conversation as resolved.
attributes(res) <- list(
Expand All @@ -334,15 +351,16 @@ unsafe_create_vs <- function(graph, idx, verts = NULL) {
#
# This is the batch form of `unsafe_create_vs()` and replaces the
# `lapply(idx_list, unsafe_create_vs, graph = graph, verts = V(graph))`
# pattern. The whole per-element loop runs in C, so building many sequences
# costs no per-object R overhead (no closure call, no `as.integer()`, no
# `attributes<-`). This is what brings construction of many sequences
# (e.g. `max_cliques()`) down close to the cost of returning bare indices.
# pattern. The per-graph work -- `V(graph)`, the shared weak reference, the
# graph id and the lazy name source -- is hoisted out of the loop, so each
# sequence only costs one `as.integer()` and one `attributes<-`. This is what
# brings construction of many sequences (e.g. `max_cliques()`) down close to
# the cost of returning bare numeric indices.
create_vs_list <- function(graph, idx_list) {
# `verts <- V(graph)` is what mints the single shared weak reference and
# graph id; build it once and hand the pieces to C, which runs the
# per-element construction loop (payload coercion, name subsetting,
# attribute setting).
# `verts <- V(graph)` is what mints the single shared weak reference and graph
Comment thread
schochastics marked this conversation as resolved.
# id; build it once and hand the pieces to C, which runs the per-element
# construction loop (payload coercion, lazy-names ALTREP, attribute setting)
# without any per-object R overhead.
verts <- V(graph)
.Call(
Rx_igraph_vs_list,
Expand Down Expand Up @@ -501,7 +519,7 @@ E <- function(
}

if ("name" %in% edge_attr_names(graph)) {
names(res) <- edge_attr(graph)$name[res]
names(res) <- lazy_index_names(edge_attr(graph)$name, res)
}
if (is_named(graph)) {
el <- ends(graph, es = res)
Expand All @@ -527,10 +545,10 @@ simple_vs_index <- function(x, i, na_ok = FALSE) {
# Set every attribute in a single `attributes<-` call rather than one
# `attr<-`/`class<-` at a time: each incremental assignment shallow-copies
# the vector, and that copying dominates when many sequences are built
# (e.g. `max_cliques()`). `names` is carried over from the subset above;
# env/graph are carried from `x`, mirroring `simple_es_index()`, so
# sequences derived from one `V(graph)` share its weak reference instead of
# each minting a fresh one.
# (e.g. `max_cliques()`). `names` is carried over from the subset above (a
# lazy ALTREP, or NULL); env/graph are carried from `x`, mirroring
# `simple_es_index()`, so sequences derived from one `V(graph)` share its
# weak reference instead of each minting a fresh one.
attributes(res) <- list(
names = attr(res, "names"),
class = "igraph.vs",
Expand Down
2 changes: 1 addition & 1 deletion man/biconnected.components.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/biconnected_components.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/graphlet_basis.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/graphlets.candidate.basis.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/k_shortest_paths.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/simple_cycles.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/stCuts.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/stMincuts.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/st_cuts.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/st_min_cuts.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ extern SEXP Rx_igraph_layout_kamada_kawai_3d(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP,
extern SEXP Rx_igraph_layout_lgl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP Rx_igraph_layout_merge_dla(SEXP, SEXP);
extern SEXP Rx_igraph_layout_reingold_tilford(SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP Rx_igraph_lazy_names(SEXP, SEXP);
extern SEXP Rx_igraph_make_weak_ref(SEXP, SEXP, SEXP);
extern SEXP Rx_igraph_maximal_cliques(SEXP, SEXP, SEXP, SEXP);
extern SEXP Rx_igraph_maximal_cliques_count(SEXP, SEXP, SEXP, SEXP);
Expand Down Expand Up @@ -1145,6 +1146,7 @@ static const R_CallMethodDef CallEntries[] = {
{"Rx_igraph_layout_lgl", (DL_FUNC) &Rx_igraph_layout_lgl, 8},
{"Rx_igraph_layout_merge_dla", (DL_FUNC) &Rx_igraph_layout_merge_dla, 2},
{"Rx_igraph_layout_reingold_tilford", (DL_FUNC) &Rx_igraph_layout_reingold_tilford, 5},
{"Rx_igraph_lazy_names", (DL_FUNC) &Rx_igraph_lazy_names, 2},
{"Rx_igraph_make_weak_ref", (DL_FUNC) &Rx_igraph_make_weak_ref, 3},
{"Rx_igraph_maximal_cliques", (DL_FUNC) &Rx_igraph_maximal_cliques, 4},
{"Rx_igraph_maximal_cliques_count", (DL_FUNC) &Rx_igraph_maximal_cliques_count, 4},
Expand Down
Loading