Skip to content

Commit cddbc55

Browse files
committed
feat: exposed igraph_is_bigraphical(), closes #708
1 parent d3100c8 commit cddbc55

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# igraph Python interface changelog
22

3+
## [master]
4+
5+
### Added
6+
7+
- Added `is_bigraphical()` to test whether a pair of integer sequences can be the degree sequence of some bipartite graph.
8+
39
## [0.10.7] - 2023-09-04
410

511
### Added

src/_igraph/igraphmodule.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,19 +520,39 @@ PyObject* igraphmodule_is_graphical_degree_sequence(PyObject *self,
520520
}
521521

522522

523+
static PyObject* igraphmodule_i_is_graphical_or_bigraphical(
524+
PyObject *self, PyObject *args, PyObject *kwds, igraph_bool_t is_bigraphical
525+
);
526+
523527
PyObject* igraphmodule_is_graphical(PyObject *self, PyObject *args, PyObject *kwds) {
524-
static char* kwlist[] = { "out_deg", "in_deg", "loops", "multiple", NULL };
528+
return igraphmodule_i_is_graphical_or_bigraphical(self, args, kwds, /* is_bigraphical = */ false);
529+
}
530+
531+
PyObject* igraphmodule_is_bigraphical(PyObject *self, PyObject *args, PyObject *kwds) {
532+
return igraphmodule_i_is_graphical_or_bigraphical(self, args, kwds, /* is_bigraphical = */ true);
533+
}
534+
535+
static PyObject* igraphmodule_i_is_graphical_or_bigraphical(
536+
PyObject *self, PyObject *args, PyObject *kwds, igraph_bool_t is_bigraphical
537+
) {
538+
static char* kwlist_graphical[] = { "out_deg", "in_deg", "loops", "multiple", NULL };
539+
static char* kwlist_bigraphical[] = { "degrees1", "degrees2", "loops", "multiple", NULL };
525540
PyObject *out_deg_o = 0, *in_deg_o = 0;
526541
PyObject *loops = Py_False, *multiple = Py_False;
527542
igraph_vector_int_t out_deg, in_deg;
528543
igraph_bool_t is_directed, result;
529544
int allowed_edge_types;
530-
531-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", kwlist,
532-
&out_deg_o, &in_deg_o, &loops, &multiple))
545+
igraph_error_t retval;
546+
547+
if (!PyArg_ParseTupleAndKeywords(
548+
args, kwds,
549+
is_bigraphical ? "OO|OO" : "O|OOO",
550+
is_bigraphical ? kwlist_bigraphical : kwlist_graphical,
551+
&out_deg_o, &in_deg_o, &loops, &multiple
552+
))
533553
return NULL;
534554

535-
is_directed = (in_deg_o != 0 && in_deg_o != Py_None);
555+
is_directed = (in_deg_o != 0 && in_deg_o != Py_None) || is_bigraphical;
536556

537557
if (igraphmodule_PyObject_to_vector_int_t(out_deg_o, &out_deg))
538558
return NULL;
@@ -550,7 +570,11 @@ PyObject* igraphmodule_is_graphical(PyObject *self, PyObject *args, PyObject *kw
550570
allowed_edge_types |= IGRAPH_MULTI_SW;
551571
}
552572

553-
if (igraph_is_graphical(&out_deg, is_directed ? &in_deg : 0, allowed_edge_types, &result)) {
573+
retval = is_bigraphical
574+
? igraph_is_bigraphical(&out_deg, is_directed ? &in_deg : 0, allowed_edge_types, &result)
575+
: igraph_is_graphical(&out_deg, is_directed ? &in_deg : 0, allowed_edge_types, &result);
576+
577+
if (retval) {
554578
igraphmodule_handle_igraph_error();
555579
igraph_vector_int_destroy(&out_deg);
556580
if (is_directed) {
@@ -794,6 +818,20 @@ static PyMethodDef igraphmodule_methods[] =
794818
"@return: C{True} if there exists some graph that can realize the given degree\n"
795819
" sequence, C{False} otherwise.\n"
796820
},
821+
{"is_bigraphical", (PyCFunction)igraphmodule_is_bigraphical,
822+
METH_VARARGS | METH_KEYWORDS,
823+
"is_bigraphical(degrees1, degrees2, loops=False, multiple=False)\n--\n\n"
824+
"Returns whether two sequences of integers can be the degree sequences of a\n"
825+
"bipartite graph.\n\n"
826+
"The bipartite graph may or may not have multiple and loop edges, depending\n"
827+
"on the allowed edge types in the remaining arguments.\n\n"
828+
"@param degrees1: the list of degrees in the first partition.\n"
829+
"@param degrees2: the list of degrees in the second partition.\n"
830+
"@param loops: whether loop edges are allowed.\n"
831+
"@param multiple: whether multiple edges are allowed.\n"
832+
"@return: C{True} if there exists some bipartite graph that can realize the\n"
833+
" given degree sequences with the given edge types, C{False} otherwise.\n"
834+
},
797835
{"is_graphical", (PyCFunction)igraphmodule_is_graphical,
798836
METH_VARARGS | METH_KEYWORDS,
799837
"is_graphical(out_deg, in_deg=None, loops=False, multiple=False)\n--\n\n"

src/igraph/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
arpack_options as default_arpack_options,
6666
community_to_membership,
6767
convex_hull,
68+
is_bigraphical,
6869
is_degree_sequence,
6970
is_graphical,
7071
is_graphical_degree_sequence,
@@ -1183,6 +1184,7 @@ def write(graph, filename, *args, **kwds):
11831184
'hsl_to_rgb',
11841185
'hsva_to_rgba',
11851186
'hsv_to_rgb',
1187+
'is_bigraphical',
11861188
'is_degree_sequence',
11871189
'is_graphical',
11881190
'is_graphical_degree_sequence',

0 commit comments

Comments
 (0)