Message Boards Message Boards

Why is my implementation of a random network slower than the built-in?

Posted 6 years ago

Hello everybody,

I wanted for accademic purposes to implement the algorithm that generate a Random Graph of the Barabasi-Albert kind. I know that there exsist already a built-in function that do exactly that, but for better understanding it I challenged myself to reproduce it.

I came up with this (relatively simple, but effective) code:

m0 = 2;(*How many edges to connect at each time step*)
n = 1000; \
(*How many nodes*)
g = CompleteGraph[m0, VertexLabels -> Automatic];
addBarabAlbert[g_Graph, m_Integer] := 
EdgeAdd[g, 
Rule[m, #] & /@ RandomSample[VertexDegree@g -> VertexList@g, m0]]
Do[g = addBarabAlbert[g, i], {i, m0, n}]

Which I think it gives me a correct solution, in fact you can see from the code below that the degree of the vertexes follow a power-law of the same nature as the one generated with the built-in wolfram function.

The only problem is that my implementation is kind of slow (compared to the built-in) and I was wondering why. Maybe knowing how I could set it up to make it faster will help me in the future with different problems.

Any ideas?

(In the attachment you find the brief code)

POSTED BY: Ektor Mariotti
2 Replies

Mathematica is a high-level language. It is much quicker and easier to implement things in Mathematica than in low-level languages like C, but it will always be much slower. I expect that the built-in method is implemented in a low-level language.

EdgeAdd is necessarily slow because for each added edge, it creates an entirely new graph. Even if you work in a low-level language, e.g. even if you would use the equivalent C function when working with the igraph C library, performance would be bad for similar reasons.

To obtain good performance, you would need to modify the graph in-place, and use a representation that can handle the operations you need efficiently, e.g. adding an edge should not trigger memory reallocation. Degrees should also be updated as you add edges, and not recomputed at every step.

For example, as a start, you could represent the graph with an adjacency matrix that already has all nodes you plan to add, but they are unconnected. Then update the matrix in-place as you add each edge.

n = 100;

am = ConstantArray[0, {n, n}];

am[[1, 2]] = am[[2, 1]] = 1;

Do[
 v = RandomChoice[Total[am] -> Range[n]];
 am[[v, k]] = am[[k, v]] = 1;
 ,
 {k, 3, n}
 ]

AdjacencyGraph[am]

I chose this method because it is both easy to implement in Mathematica, fast, and I believe even Compileable in Mathematica. But it is far from the best method. The memory requirements are $O(n^2)$. You could improve on it, but that would take more work.

If you look at how libraries like igraph implement various graph algorithms, you will see that they typically work with the representation that is best for each particular task. They often do not work with their graph data structure directly. Instead, they convert it to a suitable form, process it, then convert it back.

POSTED BY: Szabolcs Horvát
Posted 5 years ago

This makes much sense!

Yes memory pre-allocation is probably the way to go, it's a pity that the documentation don't show up the time complexity of the algorithms!

I still think that my implementation is the most straight-forward to implement, but your reply was enlightening.

Maybe working with sparse array/matrices would make it even more efficient?

I think this it's an interesting topic not for the particular case of the Barabasi-Albert, but for more in general efficiently develop algorithms for graphs.

It's a pity that one have to tradoff simplicity for efficiency.

Thanks again Szabolcs!

POSTED BY: Ektor Mariotti
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract