I need to calculate something whose value is given by the following inneficient pseudo python code:
def foo(a,b):
tmp = 0
for i in graph.nodes():
for j in graph.nodes():
tmp += c
if (i and j are neighbors):
tmp += a - c
elif (i and j are next-neighbors):
tmp += b - c
return tmp
In other words, given all the pairs of nodes, foo = a * (E = number of edges) + b * (EE = number of pairs who are not neighbors but have a common neighbor) + c * ( N(N-1)/2 – EE – E).
I tried to think on some kind of breadth first search but I couldn’t.
EDIT: more info
- the graph is not static. I constantly add and remove edges, so I can’t calculate this only once. I must constantly update the “list of next neighbors”.
- I store the graph as an adjacency matrix.
Here’s a rough idea. But first, some assumptions: 1. undirected graph 2. constant vertex-count
Your graph changes constantly. So you need to keep the number of neighbours (edges) and second-neighbours updated efficiently. The first is trivial, so let’s look at second neighbours.
Per @Patrick’s suggestion, let’s work with
A^2, and let’s see how it can be efficiently updated without recomputing it from scratch every time.A^2_ijis the number of length-two paths fromitoj, just keep in mind that it’ll have diagonal entries as well because there’s always a length-two path from a vertex to itself. If you haveA^2, you can easily count the number of second-neighbours, so let’s keep all ofA^2updated in memory while the graph changes.How to update
A^2efficiently:When you add/remove an edge, you change
Aby a matrixBthat has only two entries. Suppose we’re adding (not removing) an edge. Then(A+B)^2 = A^2 + AB + BA + B^2.Assume the edge added was
(i,j).B^2is trivial:(B^2)_ii = (B^2)_jj = 1, the rest is 0.AB = transpose(BA)so we only need to compute one of the two, sayBA. It turns out that rowiofBAis rowjofAand rowjofBAis rowiofA, the rest is zero. So again, it’s fast to compute.Removing edges will be similar.
You only need the count of second-neighbours, so instead of counting how many non-zero non-diagonal entries
A^2has at each step, with some extra work you can count by how much the number of non-zero entries changes inA^2when you addAB + BA.EDIT
This whole thing explained in a different language:
Let’s keep track of the number of length-two paths between any two vertices in a matrix
M. When we add (remove) an edge betweeniandj, the number of length-two paths will increase (decrease) by one betweeniand all neighbours ofjas well asjand all neighbours ofi, soMis easy to update inO(n)time after every change to the graph.