From 4855c26f431c7ccc3a4362da249cf51bebc41507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Sat, 17 Aug 2024 13:38:46 +0000 Subject: [PATCH 1/5] chore: update C core --- vendor/source/igraph | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/source/igraph b/vendor/source/igraph index 28868a2fc..33c01b0a1 160000 --- a/vendor/source/igraph +++ b/vendor/source/igraph @@ -1 +1 @@ -Subproject commit 28868a2fc7b7203d2b7197a58ca9a3bd7c7f5b9c +Subproject commit 33c01b0a1ee5cb014bbd1077431a76bac46b7d8c From c62d81504a356ecd0c930ad55155e14866d40492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Sat, 17 Aug 2024 13:39:43 +0000 Subject: [PATCH 2/5] feat: allow selecting specific integer programming feedback arc set problem formulations --- src/_igraph/convert.c | 2 ++ src/_igraph/graphobject.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/_igraph/convert.c b/src/_igraph/convert.c index 44fe318cf..3529d6921 100644 --- a/src/_igraph/convert.c +++ b/src/_igraph/convert.c @@ -596,6 +596,8 @@ int igraphmodule_PyObject_to_fas_algorithm_t(PyObject *o, {"exact", IGRAPH_FAS_EXACT_IP}, {"exact_ip", IGRAPH_FAS_EXACT_IP}, {"ip", IGRAPH_FAS_EXACT_IP}, + {"ip_ti", IGRAPH_FAS_EXACT_IP_TI}, + {"ip_cg", IGRAPH_FAS_EXACT_IP_CG}, {0,0} }; TRANSLATE_ENUM_WITH(fas_algorithm_tt); diff --git a/src/_igraph/graphobject.c b/src/_igraph/graphobject.c index 6322969fa..9d696c905 100644 --- a/src/_igraph/graphobject.c +++ b/src/_igraph/graphobject.c @@ -15442,8 +15442,12 @@ struct PyMethodDef igraphmodule_Graph_methods[] = { " breaking heuristic of Eades, Lin and Smyth, which is linear in the number\n" " of edges but not necessarily optimal; however, it guarantees that the\n" " number of edges to be removed is smaller than |E|/2 - |V|/6. C{\"ip\"} uses\n" - " an integer programming formulation which is guaranteed to yield an optimal\n" - " result, but is too slow for large graphs.\n" + " the most efficient available integer programming formulation which is guaranteed\n" + " to yield an optimal result. Specific integer programming formulations can be\n" + " selected using C{\"ip_ti\"} (using triangle inequalities) and C{\"ip_cg\"}\n" + " (a minimum set cover formulation using incremental constraint generation).\n" + " Note that the minimum feedback arc set problem is NP-hard, therefore all methods\n" + " that obtain exact optimal solutions are infeasibly slow on large graphs.\n" "@return: the IDs of the edges to be removed, in a list.\n\n" }, From 82ae0208ca215c13047f92a96231456cf94149d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Sat, 17 Aug 2024 16:43:42 +0000 Subject: [PATCH 3/5] feat: feedback_vertex_set() --- src/_igraph/convert.c | 13 +++++++++ src/_igraph/convert.h | 1 + src/_igraph/graphobject.c | 59 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/_igraph/convert.c b/src/_igraph/convert.c index 3529d6921..a96bc514d 100644 --- a/src/_igraph/convert.c +++ b/src/_igraph/convert.c @@ -603,6 +603,19 @@ int igraphmodule_PyObject_to_fas_algorithm_t(PyObject *o, TRANSLATE_ENUM_WITH(fas_algorithm_tt); } +/** + * \ingroup python_interface_conversion + * \brief Converts a Python object to an igraph \c igraph_fvs_algorithm_t + */ +int igraphmodule_PyObject_to_fvs_algorithm_t(PyObject *o, + igraph_fas_algorithm_t *result) { + static igraphmodule_enum_translation_table_entry_t fvs_algorithm_tt[] = { + {"ip", IGRAPH_FVS_EXACT_IP}, + {0,0} + }; + TRANSLATE_ENUM_WITH(fvs_algorithm_tt); +} + /** * \ingroup python_interface_conversion * \brief Converts a Python object to an igraph \c igraph_get_adjacency_t diff --git a/src/_igraph/convert.h b/src/_igraph/convert.h index 54094684c..22f28eb75 100644 --- a/src/_igraph/convert.h +++ b/src/_igraph/convert.h @@ -72,6 +72,7 @@ int igraphmodule_PyObject_to_community_comparison_t(PyObject *obj, int igraphmodule_PyObject_to_connectedness_t(PyObject *o, igraph_connectedness_t *result); int igraphmodule_PyObject_to_degseq_t(PyObject *o, igraph_degseq_t *result); int igraphmodule_PyObject_to_fas_algorithm_t(PyObject *o, igraph_fas_algorithm_t *result); +int igraphmodule_PyObject_to_fvs_algorithm_t(PyObject *o, igraph_fas_algorithm_t *result); int igraphmodule_PyObject_to_get_adjacency_t(PyObject *o, igraph_get_adjacency_t *result); int igraphmodule_PyObject_to_laplacian_normalization_t(PyObject *o, igraph_laplacian_normalization_t *result); int igraphmodule_PyObject_to_layout_grid_t(PyObject *o, igraph_layout_grid_t *result); diff --git a/src/_igraph/graphobject.c b/src/_igraph/graphobject.c index 9d696c905..bdcfd3d8c 100644 --- a/src/_igraph/graphobject.c +++ b/src/_igraph/graphobject.c @@ -5558,6 +5558,48 @@ PyObject *igraphmodule_Graph_feedback_arc_set( } +/** \ingroup python_interface_graph + * \brief Calculates a feedback vertex set for a graph + * \return a list containing the indices in the chosen feedback vertex set + * \sa igraph_feedback_vertex_set + */ +PyObject *igraphmodule_Graph_feedback_vertex_set( + igraphmodule_GraphObject *self, PyObject *args, PyObject *kwds) { + static char *kwlist[] = { "weights", "method", NULL }; + igraph_vector_t* weights = 0; + igraph_vector_int_t res; + igraph_fvs_algorithm_t algo = IGRAPH_FVS_EXACT_IP; + PyObject *weights_o = Py_None, *result_o = NULL, *algo_o = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &weights_o, &algo_o)) + return NULL; + + if (igraphmodule_PyObject_to_fvs_algorithm_t(algo_o, &algo)) + return NULL; + + if (igraphmodule_attrib_to_vector_t(weights_o, self, &weights, + ATTRIBUTE_TYPE_VERTEX)) + return NULL; + + if (igraph_vector_int_init(&res, 0)) { + if (weights) { igraph_vector_destroy(weights); free(weights); } + } + + if (igraph_feedback_vertex_set(&self->g, &res, weights, algo)) { + if (weights) { igraph_vector_destroy(weights); free(weights); } + igraph_vector_int_destroy(&res); + return NULL; + } + + if (weights) { igraph_vector_destroy(weights); free(weights); } + + result_o = igraphmodule_vector_int_t_to_PyList(&res); + igraph_vector_int_destroy(&res); + + return result_o; +} + + /** \ingroup python_interface_graph * \brief Calculates a single shortest path between a source and a target vertex * \return a list containing a single shortest path from the source to the target @@ -15451,6 +15493,23 @@ struct PyMethodDef igraphmodule_Graph_methods[] = { "@return: the IDs of the edges to be removed, in a list.\n\n" }, + /* interface to igraph_feedback_vertex_set */ + {"feedback_vertex_set", (PyCFunction) igraphmodule_Graph_feedback_vertex_set, + METH_VARARGS | METH_KEYWORDS, + "feedback_vertex_set(weights=None, method=\"ip\")\n--\n\n" + "Calculates a minimum feedback vertex set.\n\n" + "A feedback vertex set is a set of edges whose removal makes the graph acyclic.\n" + "Finding a minimum feedback vertex set is an NP-hard problem both in directed\n" + "and undirected graphs.\n\n" + "@param weights: vertex weights to be used. Can be a sequence or iterable or\n" + " even a vertex attribute name. When given, the algorithm will strive to\n" + " remove lightweight vertices in order to minimize the total weight of the\n" + " feedback vertex set.\n" + "@param method: the algorithm to use. C{\"ip\"} uses an exact integer programming\n" + " approach, and is currently the only available method.\n" + "@return: the IDs of the vertices to be removed, in a list.\n\n" + }, + /* interface to igraph_get_shortest_path */ {"get_shortest_path", (PyCFunction) igraphmodule_Graph_get_shortest_path, METH_VARARGS | METH_KEYWORDS, From 93b279dd13955bd48f1996702697d40d76837b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nepusz?= Date: Tue, 3 Sep 2024 01:44:50 +0200 Subject: [PATCH 4/5] fix: fix signature of igraphmodule_PyObject_to_fvs_algorithm_t --- src/_igraph/convert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_igraph/convert.c b/src/_igraph/convert.c index a96bc514d..6ee49205c 100644 --- a/src/_igraph/convert.c +++ b/src/_igraph/convert.c @@ -608,7 +608,7 @@ int igraphmodule_PyObject_to_fas_algorithm_t(PyObject *o, * \brief Converts a Python object to an igraph \c igraph_fvs_algorithm_t */ int igraphmodule_PyObject_to_fvs_algorithm_t(PyObject *o, - igraph_fas_algorithm_t *result) { + igraph_fvs_algorithm_t *result) { static igraphmodule_enum_translation_table_entry_t fvs_algorithm_tt[] = { {"ip", IGRAPH_FVS_EXACT_IP}, {0,0} From db000723a575e96343571abd40f45d7b1f2da87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nepusz?= Date: Tue, 3 Sep 2024 01:46:53 +0200 Subject: [PATCH 5/5] fix: also fix signature here --- src/_igraph/convert.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_igraph/convert.h b/src/_igraph/convert.h index 22f28eb75..873be1dc0 100644 --- a/src/_igraph/convert.h +++ b/src/_igraph/convert.h @@ -72,7 +72,7 @@ int igraphmodule_PyObject_to_community_comparison_t(PyObject *obj, int igraphmodule_PyObject_to_connectedness_t(PyObject *o, igraph_connectedness_t *result); int igraphmodule_PyObject_to_degseq_t(PyObject *o, igraph_degseq_t *result); int igraphmodule_PyObject_to_fas_algorithm_t(PyObject *o, igraph_fas_algorithm_t *result); -int igraphmodule_PyObject_to_fvs_algorithm_t(PyObject *o, igraph_fas_algorithm_t *result); +int igraphmodule_PyObject_to_fvs_algorithm_t(PyObject *o, igraph_fvs_algorithm_t *result); int igraphmodule_PyObject_to_get_adjacency_t(PyObject *o, igraph_get_adjacency_t *result); int igraphmodule_PyObject_to_laplacian_normalization_t(PyObject *o, igraph_laplacian_normalization_t *result); int igraphmodule_PyObject_to_layout_grid_t(PyObject *o, igraph_layout_grid_t *result);