Skip to content

Commit

Permalink
Merge pull request #792 from igraph/feat/fvs
Browse files Browse the repository at this point in the history
feat: `feedback_vertex_set()`
  • Loading branch information
ntamas authored Sep 4, 2024
2 parents f3647cb + accc484 commit c5baade
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 3 deletions.
15 changes: 15 additions & 0 deletions src/_igraph/convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,11 +600,26 @@ 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);
}

/**
* \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_fvs_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
Expand Down
1 change: 1 addition & 0 deletions src/_igraph/convert.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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);
Expand Down
67 changes: 65 additions & 2 deletions src/_igraph/graphobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -15445,11 +15487,32 @@ 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"
},

/* 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,
Expand Down

0 comments on commit c5baade

Please sign in to comment.