From e42f2c2469a2538be47985b81d64e6cd07e256f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Mon, 21 Oct 2024 20:10:35 +0000 Subject: [PATCH] feat: `feedback_vertex_set()` finds a minimum feedback vertex set in a graph --- NAMESPACE | 1 + R/aaa-auto.R | 22 ++++++++++ R/structural.properties.R | 31 ++++++++++++++ man/bfs.Rd | 1 + man/components.Rd | 1 + man/constraint.Rd | 1 + man/coreness.Rd | 1 + man/degree.Rd | 1 + man/dfs.Rd | 1 + man/distances.Rd | 1 + man/edge_density.Rd | 1 + man/ego.Rd | 1 + man/feedback_arc_set.Rd | 2 + man/feedback_vertex_set.Rd | 76 +++++++++++++++++++++++++++++++++ man/girth.Rd | 2 + man/has_eulerian_path.Rd | 1 + man/is_acyclic.Rd | 2 + man/is_dag.Rd | 2 + man/k_shortest_paths.Rd | 1 + man/knn.Rd | 1 + man/matching.Rd | 1 + man/reciprocity.Rd | 1 + man/subcomponent.Rd | 1 + man/subgraph.Rd | 1 + man/topo_sort.Rd | 1 + man/transitivity.Rd | 1 + man/unfold_tree.Rd | 1 + man/which_multiple.Rd | 1 + man/which_mutual.Rd | 1 + src/cpp11.cpp | 2 + src/rinterface.c | 33 ++++++++++++++ tools/stimulus/functions-R.yaml | 1 - tools/stimulus/types-RR.yaml | 6 +++ 33 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 man/feedback_vertex_set.Rd diff --git a/NAMESPACE b/NAMESPACE index d1c40956c1..f0fd539609 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -348,6 +348,7 @@ export(farthest.nodes) export(farthest_vertices) export(fastgreedy.community) export(feedback_arc_set) +export(feedback_vertex_set) export(fit_hrg) export(fit_power_law) export(forest.fire.game) diff --git a/R/aaa-auto.R b/R/aaa-auto.R index 3f0020c9e4..3d8682c8cf 100644 --- a/R/aaa-auto.R +++ b/R/aaa-auto.R @@ -1231,6 +1231,28 @@ feedback_arc_set_impl <- function(graph, weights=NULL, algo=c("approx_eades", "e res } +feedback_vertex_set_impl <- function(graph, weights=NULL, algo=c("exact_ip")) { + # Argument checks + ensure_igraph(graph) + if (is.null(weights) && "weight" %in% vertex_attr_names(graph)) { + weights <- V(graph)$weight + } + if (!is.null(weights) && any(!is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } + algo <- switch(igraph.match.arg(algo), "exact_ip"=0L) + + on.exit( .Call(R_igraph_finalizer) ) + # Function call + res <- .Call(R_igraph_feedback_vertex_set, graph, weights, algo) + if (igraph_opt("return.vs.es")) { + res <- create_vs(graph, res) + } + res +} + is_loop_impl <- function(graph, eids=E(graph)) { # Argument checks ensure_igraph(graph) diff --git a/R/structural.properties.R b/R/structural.properties.R index ca1029e142..0dae75d01c 100644 --- a/R/structural.properties.R +++ b/R/structural.properties.R @@ -1878,6 +1878,37 @@ topo_sort <- function(graph, mode = c("out", "all", "in")) { #' @cdocs igraph_feedback_arc_set feedback_arc_set <- feedback_arc_set_impl +#' Finding a feedback vertex set in a graph +#' +#' @description +#' `r lifecycle::badge("experimental")` +#' +#' A feedback vertex set of a graph is a subset of vertices whose removal breaks +#' all cycles in the graph. Finding a _minimum_ feedback vertex set is an +#' NP-complete problem, both on directed and undirected graphs. +#' +#' @param graph The input graph +#' @param weights Potential vertex weights. If the graph has a vertex +#' attribute called \sQuote{`weight`}, and this argument is +#' `NULL`, then the vertex attribute is used automatically. The goal of +#' the feedback vertex set problem is to find a feedback vertex set with +#' the smallest total weight. +#' @param algo Specifies the algorithm to use. Currently, \dQuote{`exact_ip`}, +#' which solves the feedback vertex set problem with an exact integer +#' programming approach, is the only option. +#' @return A vertex sequence (by default, but see the `return.vs.es` option +#' of [igraph_options()]) containing the feedback vertex set. +#' @keywords graphs +#' @family structural.properties +#' @family cycles +#' @export +#' @examples +#' +#' g <- make_lattice(c(3,3)) +#' feedback_vertex_set(g) +#' @cdocs igraph_feedback_vertex_set +feedback_vertex_set <- feedback_vertex_set_impl + #' Girth of a graph #' #' The girth of a graph is the length of the shortest circle in it. diff --git a/man/bfs.Rd b/man/bfs.Rd index 17046dd69f..aeba03dfdb 100644 --- a/man/bfs.Rd +++ b/man/bfs.Rd @@ -153,6 +153,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/components.Rd b/man/components.Rd index 9db9505734..a7c1f42b58 100644 --- a/man/components.Rd +++ b/man/components.Rd @@ -102,6 +102,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/constraint.Rd b/man/constraint.Rd index 8547fd7dbb..00f4e61f95 100644 --- a/man/constraint.Rd +++ b/man/constraint.Rd @@ -62,6 +62,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/coreness.Rd b/man/coreness.Rd index 248499a638..afcf599131 100644 --- a/man/coreness.Rd +++ b/man/coreness.Rd @@ -57,6 +57,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/degree.Rd b/man/degree.Rd index 6292374fc2..957d95b2d2 100644 --- a/man/degree.Rd +++ b/man/degree.Rd @@ -80,6 +80,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/dfs.Rd b/man/dfs.Rd index 7c72023e08..b906bd2ec2 100644 --- a/man/dfs.Rd +++ b/man/dfs.Rd @@ -134,6 +134,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/distances.Rd b/man/distances.Rd index 36a86e62dd..ded337a86c 100644 --- a/man/distances.Rd +++ b/man/distances.Rd @@ -273,6 +273,7 @@ Other structural.properties: \code{\link{dfs}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/edge_density.Rd b/man/edge_density.Rd index ddbaf008e5..7be9ecca90 100644 --- a/man/edge_density.Rd +++ b/man/edge_density.Rd @@ -59,6 +59,7 @@ Other structural.properties: \code{\link{dfs}()}, \code{\link{distance_table}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/ego.Rd b/man/ego.Rd index b6cb5e6413..8cf45b8669 100644 --- a/man/ego.Rd +++ b/man/ego.Rd @@ -184,6 +184,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/feedback_arc_set.Rd b/man/feedback_arc_set.Rd index fdc6fae4b1..0e35d76373 100644 --- a/man/feedback_arc_set.Rd +++ b/man/feedback_arc_set.Rd @@ -60,6 +60,7 @@ Other structural.properties: \code{\link{dfs}()}, \code{\link{distance_table}()}, \code{\link{edge_density}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, @@ -76,6 +77,7 @@ Other structural.properties: \code{\link{which_mutual}()} Graph cycles +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{has_eulerian_path}()}, \code{\link{is_acyclic}()}, diff --git a/man/feedback_vertex_set.Rd b/man/feedback_vertex_set.Rd new file mode 100644 index 0000000000..d4085896ef --- /dev/null +++ b/man/feedback_vertex_set.Rd @@ -0,0 +1,76 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/structural.properties.R +\name{feedback_vertex_set} +\alias{feedback_vertex_set} +\title{Finding a feedback vertex set in a graph} +\usage{ +feedback_vertex_set(graph, weights = NULL, algo = c("exact_ip")) +} +\arguments{ +\item{graph}{The input graph} + +\item{weights}{Potential vertex weights. If the graph has a vertex +attribute called \sQuote{\code{weight}}, and this argument is +\code{NULL}, then the vertex attribute is used automatically. The goal of +the feedback vertex set problem is to find a feedback vertex set with +the smallest total weight.} + +\item{algo}{Specifies the algorithm to use. Currently, \dQuote{\code{exact_ip}}, +which solves the feedback vertex set problem with an exact integer +programming approach, is the only option.} +} +\value{ +A vertex sequence (by default, but see the \code{return.vs.es} option +of \code{\link[=igraph_options]{igraph_options()}}) containing the feedback vertex set. +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} + +A feedback vertex set of a graph is a subset of vertices whose removal breaks +all cycles in the graph. Finding a \emph{minimum} feedback vertex set is an +NP-complete problem, both on directed and undirected graphs. +} +\examples{ + +g <- make_lattice(c(3,3)) +feedback_vertex_set(g) +} +\seealso{ +Other structural.properties: +\code{\link{bfs}()}, +\code{\link{component_distribution}()}, +\code{\link{connect}()}, +\code{\link{constraint}()}, +\code{\link{coreness}()}, +\code{\link{degree}()}, +\code{\link{dfs}()}, +\code{\link{distance_table}()}, +\code{\link{edge_density}()}, +\code{\link{feedback_arc_set}()}, +\code{\link{girth}()}, +\code{\link{is_acyclic}()}, +\code{\link{is_dag}()}, +\code{\link{is_matching}()}, +\code{\link{k_shortest_paths}()}, +\code{\link{knn}()}, +\code{\link{reciprocity}()}, +\code{\link{subcomponent}()}, +\code{\link{subgraph}()}, +\code{\link{topo_sort}()}, +\code{\link{transitivity}()}, +\code{\link{unfold_tree}()}, +\code{\link{which_multiple}()}, +\code{\link{which_mutual}()} + +Graph cycles +\code{\link{feedback_arc_set}()}, +\code{\link{girth}()}, +\code{\link{has_eulerian_path}()}, +\code{\link{is_acyclic}()}, +\code{\link{is_dag}()} +} +\concept{cycles} +\concept{structural.properties} +\keyword{graphs} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_feedback_vertex_set}{\code{igraph_feedback_vertex_set()}}.} + diff --git a/man/girth.Rd b/man/girth.Rd index a3040aee40..fbc8f83b60 100644 --- a/man/girth.Rd +++ b/man/girth.Rd @@ -62,6 +62,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, \code{\link{is_matching}()}, @@ -78,6 +79,7 @@ Other structural.properties: Graph cycles \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{has_eulerian_path}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()} diff --git a/man/has_eulerian_path.Rd b/man/has_eulerian_path.Rd index 275cf63241..62beee753c 100644 --- a/man/has_eulerian_path.Rd +++ b/man/has_eulerian_path.Rd @@ -59,6 +59,7 @@ try(eulerian_cycle(g)) \seealso{ Graph cycles \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()} diff --git a/man/is_acyclic.Rd b/man/is_acyclic.Rd index c00977d8c7..b2fdc9128c 100644 --- a/man/is_acyclic.Rd +++ b/man/is_acyclic.Rd @@ -31,6 +31,7 @@ and directed graphs. Graph cycles \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{has_eulerian_path}()}, \code{\link{is_dag}()} @@ -46,6 +47,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_dag}()}, \code{\link{is_matching}()}, diff --git a/man/is_dag.Rd b/man/is_dag.Rd index 8391020f74..91516c09d4 100644 --- a/man/is_dag.Rd +++ b/man/is_dag.Rd @@ -31,6 +31,7 @@ is_dag(g2) \seealso{ Graph cycles \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{has_eulerian_path}()}, \code{\link{is_acyclic}()} @@ -46,6 +47,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_matching}()}, diff --git a/man/k_shortest_paths.Rd b/man/k_shortest_paths.Rd index 089d446917..4a849cd188 100644 --- a/man/k_shortest_paths.Rd +++ b/man/k_shortest_paths.Rd @@ -70,6 +70,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/knn.Rd b/man/knn.Rd index e3d3a6ab4f..e9027af866 100644 --- a/man/knn.Rd +++ b/man/knn.Rd @@ -100,6 +100,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/matching.Rd b/man/matching.Rd index 5b8949afcd..85aa206b74 100644 --- a/man/matching.Rd +++ b/man/matching.Rd @@ -122,6 +122,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/reciprocity.Rd b/man/reciprocity.Rd index 4563ab737c..a902cafef3 100644 --- a/man/reciprocity.Rd +++ b/man/reciprocity.Rd @@ -53,6 +53,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/subcomponent.Rd b/man/subcomponent.Rd index 576026c43d..6c54e01146 100644 --- a/man/subcomponent.Rd +++ b/man/subcomponent.Rd @@ -49,6 +49,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/subgraph.Rd b/man/subgraph.Rd index 38f954b99b..4faf75ed1d 100644 --- a/man/subgraph.Rd +++ b/man/subgraph.Rd @@ -76,6 +76,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/topo_sort.Rd b/man/topo_sort.Rd index 31c783af8d..b74e897e5c 100644 --- a/man/topo_sort.Rd +++ b/man/topo_sort.Rd @@ -48,6 +48,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/transitivity.Rd b/man/transitivity.Rd index 48bb8347a6..6ac9f6c86d 100644 --- a/man/transitivity.Rd +++ b/man/transitivity.Rd @@ -130,6 +130,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/unfold_tree.Rd b/man/unfold_tree.Rd index dc92393559..d46f37d1b3 100644 --- a/man/unfold_tree.Rd +++ b/man/unfold_tree.Rd @@ -55,6 +55,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/which_multiple.Rd b/man/which_multiple.Rd index 8dcfbc305c..c7d3886570 100644 --- a/man/which_multiple.Rd +++ b/man/which_multiple.Rd @@ -96,6 +96,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/man/which_mutual.Rd b/man/which_mutual.Rd index f047cc424c..38bbd71a57 100644 --- a/man/which_mutual.Rd +++ b/man/which_mutual.Rd @@ -53,6 +53,7 @@ Other structural.properties: \code{\link{distance_table}()}, \code{\link{edge_density}()}, \code{\link{feedback_arc_set}()}, +\code{\link{feedback_vertex_set}()}, \code{\link{girth}()}, \code{\link{is_acyclic}()}, \code{\link{is_dag}()}, diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 8a1e3759b4..dccd97913b 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -163,6 +163,7 @@ extern SEXP R_igraph_extended_chordal_ring(SEXP, SEXP, SEXP); extern SEXP R_igraph_famous(SEXP); extern SEXP R_igraph_farthest_points(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_feedback_arc_set(SEXP, SEXP, SEXP); +extern SEXP R_igraph_feedback_vertex_set(SEXP, SEXP, SEXP); extern SEXP R_igraph_finalizer(void); extern SEXP R_igraph_find_cycle(SEXP, SEXP); extern SEXP R_igraph_forest_fire_game(SEXP, SEXP, SEXP, SEXP, SEXP); @@ -616,6 +617,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_famous", (DL_FUNC) &R_igraph_famous, 1}, {"R_igraph_farthest_points", (DL_FUNC) &R_igraph_farthest_points, 4}, {"R_igraph_feedback_arc_set", (DL_FUNC) &R_igraph_feedback_arc_set, 3}, + {"R_igraph_feedback_vertex_set", (DL_FUNC) &R_igraph_feedback_vertex_set, 3}, {"R_igraph_finalizer", (DL_FUNC) &R_igraph_finalizer, 0}, {"R_igraph_find_cycle", (DL_FUNC) &R_igraph_find_cycle, 2}, {"R_igraph_forest_fire_game", (DL_FUNC) &R_igraph_forest_fire_game, 5}, diff --git a/src/rinterface.c b/src/rinterface.c index dc9615cf15..f45aa23c0c 100644 --- a/src/rinterface.c +++ b/src/rinterface.c @@ -3755,6 +3755,39 @@ SEXP R_igraph_feedback_arc_set(SEXP graph, SEXP weights, SEXP algo) { return(r_result); } +/*-------------------------------------------/ +/ igraph_feedback_vertex_set / +/-------------------------------------------*/ +SEXP R_igraph_feedback_vertex_set(SEXP graph, SEXP weights, SEXP algo) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_int_t c_result; + igraph_vector_t c_weights; + igraph_fvs_algorithm_t c_algo; + SEXP result; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (0 != igraph_vector_int_init(&c_result, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_result); + if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } + c_algo = (igraph_fvs_algorithm_t) Rf_asInteger(algo); + /* Call igraph */ + IGRAPH_R_CHECK(igraph_feedback_vertex_set(&c_graph, &c_result, (Rf_isNull(weights) ? 0 : &c_weights), c_algo)); + + /* Convert output */ + PROTECT(result=R_igraph_vector_int_to_SEXPp1(&c_result)); + igraph_vector_int_destroy(&c_result); + IGRAPH_FINALLY_CLEAN(1); + r_result = result; + + UNPROTECT(1); + return(r_result); +} + /*-------------------------------------------/ / igraph_is_loop / /-------------------------------------------*/ diff --git a/tools/stimulus/functions-R.yaml b/tools/stimulus/functions-R.yaml index e9332a844f..f0553a7326 100644 --- a/tools/stimulus/functions-R.yaml +++ b/tools/stimulus/functions-R.yaml @@ -511,7 +511,6 @@ igraph_topological_sorting: igraph_feedback_arc_set: igraph_feedback_vertex_set: - IGNORE: RR, RC igraph_is_loop: PARAM_NAMES: diff --git a/tools/stimulus/types-RR.yaml b/tools/stimulus/types-RR.yaml index c72ed787de..2f32a6a7b1 100644 --- a/tools/stimulus/types-RR.yaml +++ b/tools/stimulus/types-RR.yaml @@ -458,6 +458,12 @@ FAS_ALGORITHM: INCONV: |- %I% <- switch(igraph.match.arg(%I%), "exact_ip"=0L, "approx_eades"=1L) +FVS_ALGORITHM: + DEFAULT: + EXACT_IP: c("exact_ip") + INCONV: |- + %I% <- switch(igraph.match.arg(%I%), "exact_ip"=0L) + WHEEL_MODE: DEFAULT: OUT: c("out", "in", "undirected", "mutual")