From 5b53d4385942d7051693cf2320e76a0b8e9632f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Mon, 11 Nov 2024 13:58:12 +0000 Subject: [PATCH 1/2] feat: `is_complete()` checks if a graph is complete --- NAMESPACE | 1 + R/cliques.R | 23 +++++++++++++++++++++++ man/cliques.Rd | 1 + man/is_complete.Rd | 40 ++++++++++++++++++++++++++++++++++++++++ man/ivs.Rd | 1 + man/weighted_cliques.Rd | 1 + 6 files changed, 67 insertions(+) create mode 100644 man/is_complete.Rd diff --git a/NAMESPACE b/NAMESPACE index d1c40956c1..7c071643ec 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -548,6 +548,7 @@ export(is_acyclic) export(is_biconnected) export(is_bipartite) export(is_chordal) +export(is_complete) export(is_connected) export(is_dag) export(is_degseq) diff --git a/R/cliques.R b/R/cliques.R index dfc97b2276..0c771887d6 100644 --- a/R/cliques.R +++ b/R/cliques.R @@ -527,3 +527,26 @@ clique_size_counts <- function(graph, min = 0, max = 0, maximal = FALSE) { clique_size_hist_impl(graph, min, max) } } + +#' Is this a complete graph? +#' +#' A graph is considered complete if there is an edge between all distinct +#' directed pairs of vertices. igraph considers both the singleton graph +#' and the null graph complete. +#' +#' @param graph The input graph. +#' @return True if the graph is complete. +#' @family cliques +#' @keywords graphs +#' @seealso [make_full_graph()] +#' @export +#' @cdocs igraph_is_complete +#' @examples +#' +#' g <- make_full_graph(6, directed = TRUE) +#' is_complete(g) +#' g <- delete_edges(g, 1) +#' is_complete(g) +#' g <- as_undirected(g) +#' is_complete(g) +is_complete <- is_complete_impl diff --git a/man/cliques.Rd b/man/cliques.Rd index 4f422b38d8..fcc8eb5c86 100644 --- a/man/cliques.Rd +++ b/man/cliques.Rd @@ -116,6 +116,7 @@ in Sparse Graphs in Near-optimal Time. \url{https://arxiv.org/abs/1006.5440} } \seealso{ Other cliques: +\code{\link{is_complete}()}, \code{\link{ivs}()}, \code{\link{weighted_cliques}()} } diff --git a/man/is_complete.Rd b/man/is_complete.Rd new file mode 100644 index 0000000000..17871af6c1 --- /dev/null +++ b/man/is_complete.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/cliques.R +\name{is_complete} +\alias{is_complete} +\title{Is this a complete graph?} +\usage{ +is_complete(graph) +} +\arguments{ +\item{graph}{The input graph.} +} +\value{ +True if the graph is complete. +} +\description{ +A graph is considered complete if there is an edge between all distinct +directed pairs of vertices. igraph considers both the singleton graph +and the null graph complete. +} +\examples{ + +g <- make_full_graph(6, directed = TRUE) +is_complete(g) +g <- delete_edges(g, 1) +is_complete(g) +g <- as_undirected(g) +is_complete(g) +} +\seealso{ +\code{\link[=make_full_graph]{make_full_graph()}} + +Other cliques: +\code{\link{cliques}()}, +\code{\link{ivs}()}, +\code{\link{weighted_cliques}()} +} +\concept{cliques} +\keyword{graphs} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_is_complete}{\code{igraph_is_complete()}}.} + diff --git a/man/ivs.Rd b/man/ivs.Rd index 667c3d3df7..74fbc9a8a2 100644 --- a/man/ivs.Rd +++ b/man/ivs.Rd @@ -86,6 +86,7 @@ Computing}, 6:505--517, 1977. \seealso{ Other cliques: \code{\link{cliques}()}, +\code{\link{is_complete}()}, \code{\link{weighted_cliques}()} } \author{ diff --git a/man/weighted_cliques.Rd b/man/weighted_cliques.Rd index 0718dd33aa..075df75ff5 100644 --- a/man/weighted_cliques.Rd +++ b/man/weighted_cliques.Rd @@ -67,6 +67,7 @@ weighted_clique_num(g) \seealso{ Other cliques: \code{\link{cliques}()}, +\code{\link{is_complete}()}, \code{\link{ivs}()} } \author{ From 3c79b175307473f5dc5c3ab1a3bb8404025a1c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Mon, 11 Nov 2024 14:10:41 +0000 Subject: [PATCH 2/2] feat: `is_clique()` and `is_ivs()` test whether a set of vertices forms a clique or an independent set --- NAMESPACE | 2 ++ R/cliques.R | 34 ++++++++++++++++++++++++++ man/clique.number.Rd | 3 +-- man/cliques.Rd | 23 ++++++++++++++--- man/independence.number.Rd | 3 +-- man/independent.vertex.sets.Rd | 3 +-- man/ivs.Rd | 15 ++++++++++-- man/largest.cliques.Rd | 3 +-- man/largest.independent.vertex.sets.Rd | 3 +-- man/maximal.cliques.Rd | 3 +-- man/maximal.cliques.count.Rd | 3 +-- man/maximal.independent.vertex.sets.Rd | 3 +-- man/maximal_ivs.Rd | 3 +-- 13 files changed, 78 insertions(+), 23 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 7c071643ec..fb0b4cd5cb 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -548,6 +548,7 @@ export(is_acyclic) export(is_biconnected) export(is_bipartite) export(is_chordal) +export(is_clique) export(is_complete) export(is_connected) export(is_dag) @@ -558,6 +559,7 @@ export(is_graphical) export(is_hierarchical) export(is_igraph) export(is_isomorphic_to) +export(is_ivs) export(is_matching) export(is_max_matching) export(is_min_separator) diff --git a/R/cliques.R b/R/cliques.R index 0c771887d6..eafeb44864 100644 --- a/R/cliques.R +++ b/R/cliques.R @@ -164,6 +164,8 @@ clique.number <- function(graph) { # nocov start #' `clique_size_counts()` returns a numeric vector representing a histogram #' of clique sizes, between the given minimum and maximum clique size. #' +#' `is_clique()` tests whether all pairs within a vertex set are connected. +#' #' @inheritParams weighted_cliques #' @param graph The input graph, directed graphs will be considered as #' undirected ones, multiple edges and loops are ignored. @@ -205,6 +207,9 @@ clique.number <- function(graph) { # nocov start #' # To have a bit less maximal cliques, about 100-200 usually #' g <- sample_gnp(100, 0.03) #' max_cliques(g) +#' +#' # Check that all returned vertex sets are indeed cliques +#' all(sapply(max_cliques(g), function (c) is_clique(g, c))) #' @cdocs igraph_cliques cliques <- cliques_impl @@ -395,6 +400,8 @@ weighted_clique_num <- weighted_clique_number_impl #' These functions use the algorithm described by Tsukiyama et al., see #' reference below. #' +#' `is_ivs()` tests if no pairs within a vertex set are connected. +#' #' @param graph The input graph, directed graphs are considered as undirected, #' loop edges and multiple edges are ignored. #' @param min Numeric constant, limit for the minimum size of the independent @@ -550,3 +557,30 @@ clique_size_counts <- function(graph, min = 0, max = 0, maximal = FALSE) { #' g <- as_undirected(g) #' is_complete(g) is_complete <- is_complete_impl + +#' @rdname cliques +#' +#' @description +#' Tests if all pairs within a set of vertices are adjacent, i.e. whether they +#' form a clique. An empty set and singleton set are considered to be a clique. +#' +#' @param graph The input graph. +#' @param candidate The vertex set to test for being a clique. +#' @param directed Whether to consider edge directions. +#' @return `is_clique()` returns `TRUE` if the candidate vertex set forms +#' a clique. +#' @keywords graphs +#' @export +#' @cdocs igraph_is_clique +is_clique <- is_clique_impl + +#' @rdname ivs +#' +#' @param graph The input graph. +#' @param candidate The vertex set to test for being an independent set. +#' @return `is_ivs()` returns `TRUE` if the candidate vertex set forms an +#' independent set. +#' @keywords graphs +#' @export +#' @cdocs igraph_is_independent_vertex_set +is_ivs <- is_independent_vertex_set_impl diff --git a/man/clique.number.Rd b/man/clique.number.Rd index 19de05ff15..ae8343274c 100644 --- a/man/clique.number.Rd +++ b/man/clique.number.Rd @@ -7,8 +7,7 @@ clique.number(graph) } \arguments{ -\item{graph}{The input graph, directed graphs will be considered as -undirected ones, multiple edges and loops are ignored.} +\item{graph}{The input graph.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} diff --git a/man/cliques.Rd b/man/cliques.Rd index fcc8eb5c86..f76be0d68b 100644 --- a/man/cliques.Rd +++ b/man/cliques.Rd @@ -9,6 +9,7 @@ \alias{largest_weighted_cliques} \alias{weighted_clique_num} \alias{clique_size_counts} +\alias{is_clique} \title{Functions to find cliques, i.e. complete subgraphs in a graph} \usage{ cliques(graph, min = 0, max = 0) @@ -26,10 +27,11 @@ largest_weighted_cliques(graph, vertex.weights = NULL) weighted_clique_num(graph, vertex.weights = NULL) clique_size_counts(graph, min = 0, max = 0, maximal = FALSE) + +is_clique(graph, candidate, directed = FALSE) } \arguments{ -\item{graph}{The input graph, directed graphs will be considered as -undirected ones, multiple edges and loops are ignored.} +\item{graph}{The input graph.} \item{min}{Numeric constant, lower limit on the size of the cliques to find. \code{NULL} means no limit, i.e. it is the same as 0.} @@ -57,6 +59,10 @@ of the weighted clique finder supports positive integer weights only.} \item{maximal}{Specifies whether to look for all weighted cliques (\code{FALSE}) or only the maximal ones (\code{TRUE}).} + +\item{candidate}{The vertex set to test for being a clique.} + +\item{directed}{Whether to consider edge directions.} } \value{ \code{cliques()}, \code{largest_cliques()} and \code{clique_num()} @@ -73,10 +79,16 @@ scalar. \code{clique_size_counts()} returns a numeric vector with the clique sizes such that the i-th item belongs to cliques of size i. Trailing zeros are currently truncated, but this might change in future versions. + +\code{is_clique()} returns \code{TRUE} if the candidate vertex set forms +a clique. } \description{ These functions find all, the largest or all the maximal cliques in an undirected graph. The size of the largest clique can also be calculated. + +Tests if all pairs within a set of vertices are adjacent, i.e. whether they +form a clique. An empty set and singleton set are considered to be a clique. } \details{ \code{cliques()} find all complete subgraphs in the input graph, obeying the @@ -96,6 +108,8 @@ largest. \code{clique_size_counts()} returns a numeric vector representing a histogram of clique sizes, between the given minimum and maximum clique size. + +\code{is_clique()} tests whether all pairs within a vertex set are connected. } \examples{ @@ -108,6 +122,9 @@ largest_cliques(g) # To have a bit less maximal cliques, about 100-200 usually g <- sample_gnp(100, 0.03) max_cliques(g) + +# Check that all returned vertex sets are indeed cliques +all(sapply(max_cliques(g), function (c) is_clique(g, c))) } \references{ For maximal cliques the following algorithm is implemented: @@ -126,5 +143,5 @@ Tamas Nepusz \email{ntamas@gmail.com} and Gabor Csardi } \concept{cliques} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_cliques}{\code{igraph_cliques()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_largest_cliques}{\code{igraph_largest_cliques()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_clique_number}{\code{igraph_clique_number()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_largest_weighted_cliques}{\code{igraph_largest_weighted_cliques()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_weighted_clique_number}{\code{igraph_weighted_clique_number()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_maximal_cliques_hist}{\code{igraph_maximal_cliques_hist()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_clique_size_hist}{\code{igraph_clique_size_hist()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_cliques}{\code{igraph_cliques()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_largest_cliques}{\code{igraph_largest_cliques()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_clique_number}{\code{igraph_clique_number()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_largest_weighted_cliques}{\code{igraph_largest_weighted_cliques()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_weighted_clique_number}{\code{igraph_weighted_clique_number()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_maximal_cliques_hist}{\code{igraph_maximal_cliques_hist()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_clique_size_hist}{\code{igraph_clique_size_hist()}}, \href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_is_clique}{\code{igraph_is_clique()}}.} diff --git a/man/independence.number.Rd b/man/independence.number.Rd index 0c31fbea55..23d7d3f336 100644 --- a/man/independence.number.Rd +++ b/man/independence.number.Rd @@ -7,8 +7,7 @@ independence.number(graph) } \arguments{ -\item{graph}{The input graph, directed graphs are considered as undirected, -loop edges and multiple edges are ignored.} +\item{graph}{The input graph.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} diff --git a/man/independent.vertex.sets.Rd b/man/independent.vertex.sets.Rd index c1c2b5f300..a400e074a2 100644 --- a/man/independent.vertex.sets.Rd +++ b/man/independent.vertex.sets.Rd @@ -7,8 +7,7 @@ independent.vertex.sets(graph, min = NULL, max = NULL) } \arguments{ -\item{graph}{The input graph, directed graphs are considered as undirected, -loop edges and multiple edges are ignored.} +\item{graph}{The input graph.} \item{min}{Numeric constant, limit for the minimum size of the independent vertex sets to find. \code{NULL} means no limit.} diff --git a/man/ivs.Rd b/man/ivs.Rd index 74fbc9a8a2..30240daf59 100644 --- a/man/ivs.Rd +++ b/man/ivs.Rd @@ -6,6 +6,7 @@ \alias{max_ivs} \alias{ivs_size} \alias{independence_number} +\alias{is_ivs} \title{Independent vertex sets} \usage{ ivs(graph, min = NULL, max = NULL) @@ -17,16 +18,19 @@ max_ivs(graph) ivs_size(graph) independence_number(graph) + +is_ivs(graph, candidate) } \arguments{ -\item{graph}{The input graph, directed graphs are considered as undirected, -loop edges and multiple edges are ignored.} +\item{graph}{The input graph.} \item{min}{Numeric constant, limit for the minimum size of the independent vertex sets to find. \code{NULL} means no limit.} \item{max}{Numeric constant, limit for the maximum size of the independent vertex sets to find. \code{NULL} means no limit.} + +\item{candidate}{The vertex set to test for being an independent set.} } \value{ \code{ivs()}, @@ -35,6 +39,9 @@ vertex sets to find. \code{NULL} means no limit.} vertex ids, each list element is an independent vertex set. \code{ivs_size()} returns an integer constant. + +\code{is_ivs()} returns \code{TRUE} if the candidate vertex set forms an +independent set. } \description{ A vertex set is called independent if there no edges between any two @@ -62,6 +69,8 @@ vertex set(s). These functions use the algorithm described by Tsukiyama et al., see reference below. + +\code{is_ivs()} tests if no pairs within a vertex set are connected. } \examples{ @@ -97,3 +106,5 @@ page. } \concept{cliques} \keyword{graphs} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cliques.html#igraph_is_independent_vertex_set}{\code{igraph_is_independent_vertex_set()}}.} + diff --git a/man/largest.cliques.Rd b/man/largest.cliques.Rd index 53de329367..7ad65f633f 100644 --- a/man/largest.cliques.Rd +++ b/man/largest.cliques.Rd @@ -7,8 +7,7 @@ largest.cliques(graph) } \arguments{ -\item{graph}{The input graph, directed graphs will be considered as -undirected ones, multiple edges and loops are ignored.} +\item{graph}{The input graph.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} diff --git a/man/largest.independent.vertex.sets.Rd b/man/largest.independent.vertex.sets.Rd index 384fd15f54..0e57e435b7 100644 --- a/man/largest.independent.vertex.sets.Rd +++ b/man/largest.independent.vertex.sets.Rd @@ -7,8 +7,7 @@ largest.independent.vertex.sets(graph) } \arguments{ -\item{graph}{The input graph, directed graphs are considered as undirected, -loop edges and multiple edges are ignored.} +\item{graph}{The input graph.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} diff --git a/man/maximal.cliques.Rd b/man/maximal.cliques.Rd index 191e3aa909..f00d9668cd 100644 --- a/man/maximal.cliques.Rd +++ b/man/maximal.cliques.Rd @@ -7,8 +7,7 @@ maximal.cliques(graph, min = NULL, max = NULL, subset = NULL, file = NULL) } \arguments{ -\item{graph}{The input graph, directed graphs will be considered as -undirected ones, multiple edges and loops are ignored.} +\item{graph}{The input graph.} \item{min}{Numeric constant, lower limit on the size of the cliques to find. \code{NULL} means no limit, i.e. it is the same as 0.} diff --git a/man/maximal.cliques.count.Rd b/man/maximal.cliques.count.Rd index 840a7e0db1..718282e0ae 100644 --- a/man/maximal.cliques.count.Rd +++ b/man/maximal.cliques.count.Rd @@ -7,8 +7,7 @@ maximal.cliques.count(graph, min = NULL, max = NULL, subset = NULL) } \arguments{ -\item{graph}{The input graph, directed graphs will be considered as -undirected ones, multiple edges and loops are ignored.} +\item{graph}{The input graph.} \item{min}{Numeric constant, lower limit on the size of the cliques to find. \code{NULL} means no limit, i.e. it is the same as 0.} diff --git a/man/maximal.independent.vertex.sets.Rd b/man/maximal.independent.vertex.sets.Rd index c1cfd4ccec..8384d3a8c6 100644 --- a/man/maximal.independent.vertex.sets.Rd +++ b/man/maximal.independent.vertex.sets.Rd @@ -7,8 +7,7 @@ maximal.independent.vertex.sets(graph) } \arguments{ -\item{graph}{The input graph, directed graphs are considered as undirected, -loop edges and multiple edges are ignored.} +\item{graph}{The input graph.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} diff --git a/man/maximal_ivs.Rd b/man/maximal_ivs.Rd index d469785305..f7cff3d19b 100644 --- a/man/maximal_ivs.Rd +++ b/man/maximal_ivs.Rd @@ -7,8 +7,7 @@ maximal_ivs(graph) } \arguments{ -\item{graph}{The input graph, directed graphs are considered as undirected, -loop edges and multiple edges are ignored.} +\item{graph}{The input graph.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}