Implementing and optimizing a simple graph metric

bearophile bearophileHUGS at lycos.com
Wed Sep 18 06:39:28 PDT 2013


Joseph Rushton Wakeling:
> http://braingam.es/2013/09/betweenness-centrality-in-dgraph/

Some small improvements:


T[] betweenness(Graph, T = double)(ref Graph g, bool[] ignore = 
null)
     if (isGraph!Graph && isFloatingPoint!T)
{
     enum T T0 = 0;
     enum T T1 = 1;
     auto centrality = 
minimallyInitializedArray!(typeof(return))(g.vertexCount);
     centrality[] = T0;
     auto stack = new size_t[g.vertexCount];
     auto sigma = minimallyInitializedArray!T(g.vertexCount);
     sigma[] = T0;
     auto delta = minimallyInitializedArray!T(g.vertexCount);
     delta[] = T0;
     auto d = minimallyInitializedArray!long(g.vertexCount);
     d[] = -1;
     auto q = VertexQueue(g.vertexCount);
     auto p = new Appender!(size_t[])[g.vertexCount];

     foreach (immutable s; 0 .. g.vertexCount)
     {
         if (ignore && ignore[s])
         {
             continue;
         }

         size_t stackLength = 0;
         assert(q.empty);
         sigma[s] = T1;
         d[s] = 0;
         q.push(s);

         while (!q.empty)
         {
             immutable size_t v = q.front;
             q.pop;
             stack[stackLength] = v;
             ++stackLength;
             foreach (immutable w; g.neighboursOut(v))
             {
                 if (ignore && ignore[w])
                 {
                     continue;
                 }

                 if (d[w] < 0)
                 {
                     q.push(w);
                     d[w] = d[v] + 1;
                     assert(sigma[w] == T0);
                     sigma[w] = sigma[v];
                     p[w].clear;
                     p[w].put(v);
                 }
                 else if (d[w] > (d[v] + 1))
                 {
                     /* w has already been encountered, but we've
                        found a shorter path to the source.  This
                        is probably only relevant to the weighted
                        case, but let's keep it here in order to
                        be ready for that update. */
                     d[w] = d[v] + 1L;
                     sigma[w] = sigma[v];
                     p[w].clear;
                     p[w].put(v);
                 }
                 else if (d[w] == (d[v] + 1))
                 {
                     sigma[w] += sigma[v];
                     p[w].put(v);
                 }
             }
         }

         while (stackLength > 0)
         {
             --stackLength;
             immutable w = stack[stackLength];
             foreach (immutable v; p[w].data)
             {
                 delta[v] += ((sigma[v] / sigma[w]) * (T1 + 
delta[w]));
             }
             if (w != s)
             {
                 centrality[w] += delta[w];
             }
             sigma[w] = T0;
             delta[w] = T0;
             d[w] = -1;
         }
     }

     static if (!g.directed)
     {
         centrality[] /= 2;
     }

     return centrality;
}


Just for a test, try to allocate all those arrays in a different 
way:
- First try a std.array.Array using the LDC2 compiler;
- Another thing to try is to allocate them on the stack using 
core.stdc.stdlib.alloca:
auto p = cast(T*)alloca(T.sizeof * g.vertexCount);
if (!p) throw new MemoryError...
auto centrality = p[0 .. g.vertexCount];
This probably can't be used for very large graphs, so you have to 
add even more logic to allocate the arrays on the C heap if they 
are too much large. This could be useful if you call 
betweenness() many many times.
- Try to optionally accept the buffers from outside.

Bye,
bearophile


More information about the Digitalmars-d-announce mailing list