Skip to content

Commit

Permalink
Add random_walk_rank
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasp85 committed Nov 22, 2023
1 parent fd9f4d0 commit a20247d
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 0 deletions.
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ export(play_preference_asym)
export(play_smallworld)
export(play_traits)
export(pull)
export(random_walk_rank)
export(rename)
export(replace_na)
export(reroute)
Expand Down Expand Up @@ -558,6 +559,8 @@ importFrom(igraph,page_rank)
importFrom(igraph,permute)
importFrom(igraph,power_centrality)
importFrom(igraph,radius)
importFrom(igraph,random_edge_walk)
importFrom(igraph,random_walk)
importFrom(igraph,reciprocity)
importFrom(igraph,sample_asym_pref)
importFrom(igraph,sample_bipartite)
Expand Down Expand Up @@ -620,6 +623,7 @@ importFrom(rlang,eval_tidy)
importFrom(rlang,is_bare_list)
importFrom(rlang,list2)
importFrom(rlang,quo)
importFrom(rlang,quo_is_null)
importFrom(rlang,quo_text)
importFrom(rlang,quos)
importFrom(rlang,sym)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
calculations
* Added `to_random_spanning_tree()` morpher
* Added `min_order` argument to `to_components()` morpher
* Added `random_walk_rank()` to perform random walks on the graph

# tidygraph 1.2.3

Expand Down
65 changes: 65 additions & 0 deletions R/random_walk.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#' Perform a random walk on the graph and return encounter rank
#'
#' A random walk is a traversal of the graph starting from a node and going a
#' number of steps by picking an edge at random (potentially weighted).
#' `random_walk()` can be called both when nodes and edges are active and will
#' adapt to return a value fitting to the currently active part. As the
#' walk order cannot be directly encoded in the graph the return value is a list
#' giving a vector of positions along the walk of each node or edge.
#'
#' @param n The number of steps to perform. If the walk gets stuck before
#' reaching this number the walk is terminated
#' @param root The node to start the walk at. If `NULL` a random node will be
#' used
#' @param mode How edges are followed in the search if the graph is directed.
#' `"out"` only follows outbound edges, `"in"` only follows inbound edges, and
#' `"all"` or `"total"` follows all edges. This is ignored for undirected
#' graphs.
#' @param weights The weights to use for edges when selecting the next step of
#' the walk. Currently only used when edges are active
#'
#' @return A list with an integer vector for each node or edge (depending on
#' what is active) each element encode the time the node/edge is encountered
#' along the walk
#'
#' @importFrom igraph random_walk random_edge_walk gorder gsize
#' @importFrom rlang enquo quo_is_null eval_tidy
#' @export
#'
#' @examples
#' graph <- create_notable("zachary")
#'
#' # Random walk returning node order
#' graph |>
#' mutate(walk_rank = random_walk_rank(200))
#'
#' # Rank edges instead
#' graph |>
#' activate(edges) |>
#' mutate(walk_rank = random_walk_rank(200))
#'
random_walk_rank <- function(n, root = NULL, mode = "out", weights = NULL) {
graph <- .G()
if (is.null(root)) {
root <- sample(gorder(graph), 1)
} else {
root <- as_node_ind(root, graph)
}
weights <- enquo(weights)
if (active(graph) == "nodes") {
if (!quo_is_null(weights)) {
cli::cli_warn('{.arg weights} is ignored when doing a random walk on nodes')
}
walk <- as.integer(random_walk(graph, root, n, mode))
len_out <- gorder(graph)
} else {
weights <- eval_tidy(weights, .E())
if (is.null(weights)) weights <- NA
walk <- as.integer(random_edge_walk(graph, root, n, weights, mode))
len_out <- gsize(graph)
}
res <- rep(list(integer()), len_out)
ord <- split(seq_len(n), walk)
res[as.integer(names(ord))] <- ord
res[focus_ind(graph, active(graph))]
}
49 changes: 49 additions & 0 deletions man/random_walk_rank.Rd

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

21 changes: 21 additions & 0 deletions tests/testthat/test-random-walk.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
test_that("random_walk_rank returns correct data", {
set.seed(1)
node_walk <- create_notable('zachary') |>
mutate(walk_rank = random_walk_rank(30, 5)) |>
pull(walk_rank)

edge_walk <- create_notable('zachary') |>
activate(edges) |>
mutate(walk_rank = random_walk_rank(30, 5)) |>
pull(walk_rank)

expect_length(node_walk, 34)
expect_length(edge_walk, 78)
expect_type(node_walk, 'list')
expect_type(edge_walk, 'list')
expect_equal(node_walk[[5]], c(1, 12))
expect_equal(edge_walk[[36]], 1:4)
expect_equal(edge_walk[[36]], 1:4)
expect_equal(node_walk[[2]], integer())
expect_equal(edge_walk[[1]], integer())
})

0 comments on commit a20247d

Please sign in to comment.