Skip to content
Merged
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
34 changes: 34 additions & 0 deletions R/bipartite.R
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ bipartite.mapping <- function(graph) {
#' @param types An optional vertex type vector to use instead of the
#' \sQuote{`type`} vertex attribute. You must supply this argument if the
#' graph has no \sQuote{`type`} vertex attribute.
#' @inheritParams rlang::args_dots_empty
#' @param multiplicity If `TRUE`, then igraph keeps the multiplicity of
#' the edges as an edge attribute called \sQuote{weight}.
#' E.g. if there is an A-C-B and also an A-D-B
Expand Down Expand Up @@ -162,11 +163,44 @@ bipartite.mapping <- function(graph) {
bipartite_projection <- function(
graph,
types = NULL,
...,
multiplicity = TRUE,
probe1 = NULL,
which = c("both", "true", "false"),
remove.type = TRUE
) {
# BEGIN GENERATED ARG_HANDLE: bipartite_projection, do not edit, see tools/generate-migrations.R
if (...length() > 0L) {
.arg_handle <- migrate_recover_args(
list(...),
current = list(
multiplicity = multiplicity,
probe1 = probe1,
which = which,
remove.type = remove.type
),
recover_new = c("multiplicity", "probe1", "which", "remove.type"),
recover_old = c("multiplicity", "probe1", "which", "remove.type"),
match_names = c("multiplicity", "probe1", "which", "remove.type"),
match_to = c("multiplicity", "probe1", "which", "remove.type"),
defaults = list(
multiplicity = TRUE,
probe1 = NULL,
which = c("both", "true", "false"),
remove.type = TRUE
),
head_args = c("graph", "types"),
fn_name = "bipartite_projection"
)
list2env(.arg_handle$values, environment())
lifecycle::deprecate_soft(
"3.0.0",
what = I(.arg_handle$what),
details = .arg_handle$details
)
}
# END GENERATED ARG_HANDLE

# Argument checks
ensure_igraph(graph)
types <- handle_vertex_type_arg(types, graph)
Expand Down
1 change: 1 addition & 0 deletions R/cycles.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#' a specific cycle.
#'
#' @param graph The input graph.
#' @inheritParams rlang::args_dots_empty
#' @param mode Character constant specifying how to handle directed graphs.
#' `out` follows edge directions, `in` follows edges in the reverse direction,
#' and `all` ignores edge directions. Ignored in undirected graphs.
Expand Down
26 changes: 26 additions & 0 deletions R/degseq.R
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ is_degseq <- function(out.deg, in.deg = NULL) {
#' the out-degree sequence for directed graphs.
#' @param in.deg `NULL` or an integer vector. For undirected graphs, it
#' should be `NULL`. For directed graphs it specifies the in-degrees.
#' @inheritParams rlang::args_dots_empty
#' @param allowed.edge.types The allowed edge types in the graph. \sQuote{simple}
#' means that neither loop nor multiple edges are allowed (i.e. the graph must be
#' simple). \sQuote{loops} means that loop edges are allowed but mutiple edges
Expand All @@ -142,8 +143,33 @@ is_degseq <- function(out.deg, in.deg = NULL) {
is_graphical <- function(
out.deg,
in.deg = NULL,
...,
allowed.edge.types = c("simple", "loops", "multi", "all")
) {
# BEGIN GENERATED ARG_HANDLE: is_graphical, do not edit, see tools/generate-migrations.R
if (...length() > 0L) {
.arg_handle <- migrate_recover_args(
list(...),
current = list(allowed.edge.types = allowed.edge.types),
recover_new = c("allowed.edge.types"),
recover_old = c("allowed.edge.types"),
match_names = c("allowed.edge.types"),
match_to = c("allowed.edge.types"),
defaults = list(
allowed.edge.types = c("simple", "loops", "multi", "all")
),
head_args = c("out.deg", "in.deg"),
fn_name = "is_graphical"
)
list2env(.arg_handle$values, environment())
lifecycle::deprecate_soft(
"3.0.0",
what = I(.arg_handle$what),
details = .arg_handle$details
)
}
# END GENERATED ARG_HANDLE

is_graphical_impl(
out_deg = out.deg,
in_deg = in.deg,
Expand Down
3 changes: 3 additions & 0 deletions man/bipartite_projection.Rd

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

3 changes: 3 additions & 0 deletions man/is_graphical.Rd

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

42 changes: 42 additions & 0 deletions tests/testthat/test-bipartite.R
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,45 @@ test_that("bipartite_projection prints a warning if the type attribute is non-lo
expect_warning(bipartite_projection(g), "logical")
expect_warning(bipartite_projection_size(g), "logical")
})

# ---- ellipsis migration: argument coverage ----------------------------------

test_that("bipartite_projection() takes all tail arguments by name", {
g <- make_full_bipartite_graph(3, 2)

# A single projection is returned, without multiplicity weights,
# and it keeps the `type` vertex attribute.
proj <- bipartite_projection(
g,
multiplicity = FALSE,
which = "false",
remove.type = FALSE
)
expect_true(is_igraph(proj))
expect_vcount(proj, 3)
expect_false("weight" %in% edge_attr_names(proj))
expect_true("type" %in% vertex_attr_names(proj))

# `probe1` puts the projection containing that vertex first,
# reversing the default order (type `FALSE` first).
# Current behaviour warns even though both projections are requested.
expect_warning(
proj_probe <- bipartite_projection(g, probe1 = 4),
"probe1"
)
expect_vcount(proj_probe[[1]], 2)
expect_vcount(proj_probe[[2]], 3)
})

test_that("bipartite_projection() recovers legacy positional arguments", {
g <- make_full_bipartite_graph(3, 2)

rlang::local_options(lifecycle_verbosity = "warning")
lifecycle::expect_deprecated(
res <- bipartite_projection(g, NULL, FALSE)
)
ref <- bipartite_projection(g, multiplicity = FALSE)
expect_identical_graphs(res[[1]], ref[[1]])
expect_identical_graphs(res[[2]], ref[[2]])
expect_false("weight" %in% edge_attr_names(res[[1]]))
})
19 changes: 19 additions & 0 deletions tests/testthat/test-degseq.R
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,22 @@ test_that("is_degseq works", {
expect_true(is_degseq(degree(g)))
expect_true(is_graphical(degree(g)))
})

# ---- ellipsis migration: argument coverage ----------------------------------

test_that("is_graphical() takes `allowed.edge.types` by name", {
# Two vertices of degree 3 need multi-edges, so the verdict flips.
expect_false(is_graphical(c(3, 3)))
expect_true(is_graphical(c(3, 3), allowed.edge.types = "multi"))
# Directed sequences pass the in-degrees as the second head argument.
expect_true(is_graphical(c(2, 0, 1), c(1, 1, 1)))
})

test_that("is_graphical() recovers legacy positional arguments", {
rlang::local_options(lifecycle_verbosity = "warning")
lifecycle::expect_deprecated(
res <- is_graphical(c(3, 3), NULL, "multi")
)
expect_identical(res, is_graphical(c(3, 3), allowed.edge.types = "multi"))
expect_true(res)
})
30 changes: 30 additions & 0 deletions tools/migrations/bipartite-degseq.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Argument-signature migrations: bipartite-degseq
# Schema: see tools/migrations/README.md. Regenerate with:
# Rscript tools/generate-migrations.R

migrations <- list(
bipartite_projection = list(
old = function(graph, types, multiplicity, probe1, which, remove.type) {},
new = function(
graph,
types = NULL,
...,
multiplicity = TRUE,
probe1 = NULL,
which = c("both", "true", "false"),
remove.type = TRUE
) {},
when = "3.0.0"
),

is_graphical = list(
old = function(out.deg, in.deg, allowed.edge.types) {},
new = function(
out.deg,
in.deg = NULL,
...,
allowed.edge.types = c("simple", "loops", "multi", "all")
) {},
when = "3.0.0"
)
)
Loading