On 28.10.2016 19:40, G. B. wrote:
Thanks for the response. Unfortunately, I have tried to derive how I should set corr(a,b) to produce the graphs I would like, but the results of my code indicate that I have not successfully done so. Hopefully you can shed some light on why my derivation does not work/where my misunderstanding persists.
The graphs I would like to build are simple, undirected two-type random graphs with an in-type linking probability between any two vertices of the same type and an across-type linking probability between any two vertices of different types. Based on your last response, I take the following to be true (my sample of code is below the derivation).
Let E = total number of edges in the graph (a constant). Let n_A = number of vertices in block A. Let n_B = number of vertices in block B.
Let E_Across = total number of edges between block A and block B. Let E_inA = total number of edges within block A. Let E_inB = total number of edges within block B.
Note that:
E_Across = (n_A*n_B)*P_out E_inA = (n_A choose 2)*P_inA E_inB = (n_B choose 2)*P_inB
where P_out is the linking probability between any two vertices of the different types, P_inA is the linking probability between any two vertices of type A, and P_inB is the linking probability between any two vertices of type B.
Then it follows from your comment ("the value returned by corr(a,b) should be proportional to the probability of an edge existing between the two groups, not two nodes that belong to the two groups. In other words, the expected total number of edges between groups a and b will be proportional to corr(a, b)") that for vertex a in block A and vertex b in block B,
corr(a,b) = k*(E_Across/E) = (k/E) * (n_A*n_B*P_out)
where k is some constant of proportionality.
Similarly, for vertices a_1 and a_2 in block A,
corr(a_1,a_2) = k*(E_inA/E) = (k/E) * ((n_A choose 2)*P_inA)
and for vertices b_1 and b_2 in block B,
corr(b_1,b_2) = k*(E_inB/E) = (k/E) * ((n_B choose 2)*P_inB).
If I want P_inA = P_inB, I rearrange the last two expressions and see that:
corr(a_1,a_2) = corr(b_1,b_2) *((n_A choose 2)/(n_B choose 2))
Finally, since I want in my model that *P_inA=P_inB=f*P_out* where f is some scaling factor, I do similar algebra and see that:
*corr(a_1,a_2) = f*corr(a,b)*((n_A choose 2)/(n_A*n_B))*. and *corr(b_1,b_2) = f*corr(a,b)*((n_B choose 2)/(n_A*n_B))*.
~~~~~~~~~
Based on this math, I wrote the following code:
N = 100 n_A = 15 n_B = 85
def combinations(n, r): return factorial(n) // factorial(r) // factorial(n-r)
def blockMaker(v): if v<n_A: return 1 else: return 0
def corr(a,b): BASE=1 f=5 if a==b: if a==1: return f*BASE*(combinations(n_A,2)/(n_A*n_B)) else: return f*BASE*(combinations(n_B,2)/(n_A*n_B)) else: return BASE
g, sT = random_graph(N, lambda: poisson(5), directed=False, model="blockmodel-traditional", block_membership= blockMaker, vertex_corr=corr,n_iter=100,persist=True)
This is overly complicated. I believe this will do what you want: # These are your parameters, use whatever you want N = 100 n = [15, 85] p_in = [.1, .03] p_out = .003 # Total number of edges, conditioned on the parameters E = 0 for a in range(2): E += p_in[a] * (n[a] * (n[a] - 1)) / 2 E += p_out * n[0] * n[1] # Avg degree ak = 2 * E / N def blockMaker(v): if v < n[0]: return 0 else: return 1 def corr(a, b): if a == b: return p_in[a] * (n[a] * (n[a] - 1)) / 2 else: return p_out * n[a] * n[b] g, b = random_graph(N, lambda: poisson(ak), directed=False, model="blockmodel-traditional", block_membership= blockMaker, vertex_corr=corr, n_iter=1000, persist=True, parallel_edges=False, self_loops=False) -- Tiago de Paula Peixoto <tiago@skewed.de>