Skip to content

Commit 3b51a80

Browse files
authored
Merge pull request #780 from igraph/feat/chung-lu-game
Add Chung-Lu model
2 parents 1a5dac3 + a5caf2b commit 3b51a80

File tree

4 files changed

+147
-1
lines changed

4 files changed

+147
-1
lines changed

src/_igraph/convert.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,20 @@ int igraphmodule_PyObject_to_bliss_sh_t(PyObject *o,
514514
TRANSLATE_ENUM_WITH(bliss_sh_tt);
515515
}
516516

517+
/**
518+
* \ingroup python_interface_conversion
519+
* \brief Converts a Python object to an igraph \c igraph_chung_lu_t
520+
*/
521+
int igraphmodule_PyObject_to_chung_lu_t(PyObject *o, igraph_chung_lu_t *result) {
522+
static igraphmodule_enum_translation_table_entry_t chung_lu_tt[] = {
523+
{"original", IGRAPH_CHUNG_LU_ORIGINAL},
524+
{"grg", IGRAPH_CHUNG_LU_GRG},
525+
{"nr", IGRAPH_CHUNG_LU_NR},
526+
{0,0}
527+
};
528+
TRANSLATE_ENUM_WITH(chung_lu_tt);
529+
}
530+
517531
/**
518532
* \ingroup python_interface_conversion
519533
* \brief Converts a Python object to an igraph \c igraph_coloring_greedy_t

src/_igraph/convert.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ int igraphmodule_PyObject_to_attribute_combination_type_t(PyObject* o,
6565
int igraphmodule_PyObject_to_barabasi_algorithm_t(PyObject *o,
6666
igraph_barabasi_algorithm_t *result);
6767
int igraphmodule_PyObject_to_bliss_sh_t(PyObject *o, igraph_bliss_sh_t *result);
68+
int igraphmodule_PyObject_to_chung_lu_t(PyObject *o, igraph_chung_lu_t *result);
6869
int igraphmodule_PyObject_to_coloring_greedy_t(PyObject *o, igraph_coloring_greedy_t *result);
6970
int igraphmodule_PyObject_to_community_comparison_t(PyObject *obj,
7071
igraph_community_comparison_t *result);

src/_igraph/graphobject.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,6 +2169,57 @@ PyObject *igraphmodule_Graph_Bipartite(PyTypeObject * type,
21692169
return (PyObject *) self;
21702170
}
21712171

2172+
/** \ingroup python_interface_graph
2173+
* \brief Generates a Chung-Lu random graph
2174+
* This is intended to be a class method in Python, so the first argument
2175+
* is the type object and not the Python igraph object (because we have
2176+
* to allocate that in this method).
2177+
*
2178+
* \return a reference to the newly generated Python igraph object
2179+
* \sa igraph_chung_lu_game
2180+
*/
2181+
PyObject *igraphmodule_Graph_Chung_Lu(PyTypeObject *type, PyObject *args, PyObject *kwds)
2182+
{
2183+
igraphmodule_GraphObject *self;
2184+
igraph_t g;
2185+
igraph_vector_t outw, inw;
2186+
igraph_chung_lu_t var = IGRAPH_CHUNG_LU_ORIGINAL;
2187+
igraph_bool_t has_inw = false;
2188+
PyObject *weight_out = NULL, *weight_in = NULL, *loops = Py_True, *variant = NULL;
2189+
2190+
static char *kwlist[] = { "out", "in_", "loops", "variant", NULL };
2191+
2192+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", kwlist,
2193+
&weight_out, &weight_in, &loops, &variant))
2194+
return NULL;
2195+
2196+
if (igraphmodule_PyObject_to_chung_lu_t(variant, &var)) return NULL;
2197+
if (igraphmodule_PyObject_to_vector_t(weight_out, &outw, /* need_non_negative */ true)) return NULL;
2198+
if (weight_in) {
2199+
if (igraphmodule_PyObject_to_vector_t(weight_in, &inw, /* need_non_negative */ true)) {
2200+
igraph_vector_destroy(&outw);
2201+
return NULL;
2202+
}
2203+
has_inw=true;
2204+
}
2205+
2206+
if (igraph_chung_lu_game(&g, &outw, has_inw ? &inw : NULL, PyObject_IsTrue(loops), var)) {
2207+
igraphmodule_handle_igraph_error();
2208+
igraph_vector_destroy(&outw);
2209+
if (has_inw)
2210+
igraph_vector_destroy(&inw);
2211+
return NULL;
2212+
}
2213+
2214+
igraph_vector_destroy(&outw);
2215+
if (has_inw)
2216+
igraph_vector_destroy(&inw);
2217+
2218+
CREATE_GRAPH_FROM_TYPE(self, g, type);
2219+
2220+
return (PyObject *) self;
2221+
}
2222+
21722223
/** \ingroup python_interface_graph
21732224
* \brief Generates a De Bruijn graph
21742225
* \sa igraph_kautz
@@ -14439,6 +14490,86 @@ struct PyMethodDef igraphmodule_Graph_methods[] = {
1443914490
" this is the case, also its orientation. Must be one of\n"
1444014491
" C{\"in\"}, C{\"out\"} and C{\"undirected\"}.\n"},
1444114492

14493+
/* interface to igraph_chung_lu_game */
14494+
{"Chung_Lu", (PyCFunction) igraphmodule_Graph_Chung_Lu,
14495+
METH_VARARGS | METH_CLASS | METH_KEYWORDS,
14496+
"Chung_Lu(out, in_=None, loops=True, variant=\"original\")\n--\n\n"
14497+
"Generates a Chung-Lu random graph.\n\n"
14498+
"In the Chung-Lu model, each pair of vertices M{i} and M{j} is connected with\n"
14499+
"independent probability M{p_{ij} = w_i w_j / S}, where M{w_i} is a weight\n"
14500+
"associated with vertex M{i} and M{S = \\sum_k w_k} is the sum of weights.\n"
14501+
"In the directed variant, vertices have both out-weights, M{w^\\text{out}},\n"
14502+
"and in-weights, M{w^\\text{in}}, with equal sums,\n"
14503+
"M{S = \\sum_k w^\\text{out}_k = \\sum_k w^\\text{in}_k}. The connection\n"
14504+
"probability between M{i} and M{j} is M{p_{ij} = w^\\text{out}_i w^\\text{in}_j / S}.\n\n"
14505+
"This model is commonly used to create random graphs with a fixed I{expected}\n"
14506+
"degree sequence. The expected degree of vertex M{i} is approximately equal\n"
14507+
"to the weight M{w_i}. Specifically, if the graph is directed and self-loops\n"
14508+
"are allowed, then the expected out- and in-degrees are precisely M{w^\\text{out}}\n"
14509+
"and M{w^\\text{in}}. If self-loops are disallowed, then the expected out-\n"
14510+
"and in-degrees are M{w^\\text{out} (S - w^\\text{in}) / S} and\n"
14511+
"M{w^\\text{in} (S - w^\\text{out}) / S}, respectively. If the graph is\n"
14512+
"undirected, then the expected degrees with and without self-loops are\n"
14513+
"M{w (S + w) / S} and M{w (S - w) / S}, respectively.\n\n"
14514+
"A limitation of the original Chung-Lu model is that when some of the\n"
14515+
"weights are large, the formula for M{p_{ij}} yields values larger than 1.\n"
14516+
"Chung and Lu's original paper exludes the use of such weights. When\n"
14517+
"M{p_{ij} > 1}, this function simply issues a warning and creates\n"
14518+
"a connection between M{i} and M{j}. However, in this case the expected degrees\n"
14519+
"will no longer relate to the weights in the manner stated above. Thus the\n"
14520+
"original Chung-Lu model cannot produce certain (large) expected degrees.\n\n"
14521+
"The overcome this limitation, this function implements additional variants of\n"
14522+
"the model, with modified expressions for the connection probability M{p_{ij}}\n"
14523+
"between vertices M{i} and M{j}. Let M{q_{ij} = w_i w_j / S}, or\n"
14524+
"M{q_{ij} = w^out_i w^in_j / S} in the directed case. All model\n"
14525+
"variants become equivalent in the limit of sparse graphs where M{q_{ij}}\n"
14526+
"approaches zero. In the original Chung-Lu model, selectable by setting\n"
14527+
"C{variant} to C{\"original\"}, M{p_{ij} = min(q_{ij}, 1)}.\n"
14528+
"The C{\"grg\"} variant, often referred to a the generalized\n"
14529+
"random graph, uses M{p_{ij} = q_{ij} / (1 + q_{ij})}, and is equivalent\n"
14530+
"to a maximum entropy model (i.e. exponential random graph model) with\n"
14531+
"a constraint on expected degrees, see Park and Newman (2004), Section B,\n"
14532+
"setting M{exp(-\\Theta_{ij}) = w_i w_j / S}. This model is also\n"
14533+
"discussed by Britton, Deijfen and Martin-Löf (2006). By virtue of being\n"
14534+
"a degree-constrained maximum entropy model, it generates graphs having\n"
14535+
"the same degree sequence with the same probability.\n"
14536+
"A third variant can be requested with C{\"nr\"}, and uses\n"
14537+
"M{p_{ij} = 1 - exp(-q_{ij})}. This is the underlying simple graph\n"
14538+
"of a multigraph model introduced by Norros and Reittu (2006).\n"
14539+
"For a discussion of these three model variants, see Section 16.4 of\n"
14540+
"Bollobás, Janson, Riordan (2007), as well as Van Der Hofstad (2013).\n\n"
14541+
"B{References:}\n\n"
14542+
" - Chung F and Lu L: Connected components in a random graph with given degree sequences.\n"
14543+
" I{Annals of Combinatorics} 6, 125-145 (2002) U{https://doi.org/10.1007/PL00012580}\n"
14544+
" - Miller JC and Hagberg A: Efficient Generation of Networks with Given Expected Degrees (2011)\n"
14545+
" U{https://doi.org/10.1007/978-3-642-21286-4_10}\n"
14546+
" - Park J and Newman MEJ: Statistical mechanics of networks.\n"
14547+
" I{Physical Review E} 70, 066117 (2004). U{https://doi.org/10.1103/PhysRevE.70.066117}\n"
14548+
" - Britton T, Deijfen M, Martin-Löf A: Generating Simple Random Graphs with Prescribed Degree Distribution.\n"
14549+
" I{J Stat Phys} 124, 1377–1397 (2006). U{https://doi.org/10.1007/s10955-006-9168-x}\n"
14550+
" - Norros I and Reittu H: On a conditionally Poissonian graph process.\n"
14551+
" I{Advances in Applied Probability} 38, 59–75 (2006).\n"
14552+
" U{https://doi.org/10.1239/aap/1143936140}\n"
14553+
" - Bollobás B, Janson S, Riordan O: The phase transition in inhomogeneous random graphs.\n"
14554+
" I{Random Struct Algorithms} 31, 3–122 (2007). U{https://doi.org/10.1002/rsa.20168}\n"
14555+
" - Van Der Hofstad R: Critical behavior in inhomogeneous random graphs.\n"
14556+
" I{Random Struct Algorithms} 42, 480–508 (2013). U{https://doi.org/10.1002/rsa.20450}\n\n"
14557+
"@param out: the vertex weights (or out-weights). In sparse graphs\n"
14558+
" these will be approximately equal to the expected (out-)degrees.\n"
14559+
"@param in_: the vertex in-weights, approximately equal to the expected\n"
14560+
" in-degrees of the graph. If omitted, the generated graph will be\n"
14561+
" undirected.\n"
14562+
"@param loops: whether to allow the generation of self-loops.\n"
14563+
"@param variant: the model variant to be used. Let M{q_{ij}=w_i w_j / S},\n"
14564+
" where M{S = \\sum_k w_k}. The following variants are available:\n"
14565+
" \n"
14566+
" - C{\"original\"} -- the original Chung-Lu model with\n"
14567+
" M{p_{ij} = min(1, q_{ij})}.\n"
14568+
" - C{\"grg\"} -- generalized random graph, a maximum entropy model with\n"
14569+
" a soft constraint on degrees, M{p_{ij} = q_{ij} / (1 + q_{ij})}\n"
14570+
" - C{\"nr\"} -- Norros and Reittu's model, M{p_{ij} = 1 - exp(-q_{ij})}\n"
14571+
},
14572+
1444214573
/* interface to igraph_degree_sequence_game */
1444314574
{"Degree_Sequence", (PyCFunction) igraphmodule_Graph_Degree_Sequence,
1444414575
METH_VARARGS | METH_CLASS | METH_KEYWORDS,

0 commit comments

Comments
 (0)