@@ -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+
523527PyObject * 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"
0 commit comments