# Why is NeighborhoodGraph so slow?

To get neighboring vertices I first tried:

gg = GridGraph[{10, 10, 10, 10}];
VertexList[NeighborhoodGraph[gg, 1, 1]] // AbsoluteTiming


{5.539308, {1, 2, 11, 101, 1001}}

But that is really slow. This is much faster and still uses the new Graph package:

Union[VertexInComponent[gg, 1, 1], VertexOutComponent[gg, 1, 1]] // AbsoluteTiming


{0.000172, {1, 2, 11, 101, 1001}}'

I believe that this mimics the NeigborhoodGraph approach above, but is still much faster than using NeighborhoodGraph:

VertexList[Subgraph[gg, Union[VertexInComponent[gg, 1, 1],
VertexOutComponent[gg, 1, 1]]]] // AbsoluteTiming


{0.000306, {1, 2, 11, 101, 1001}}

The last two approaches are also faster than NeighborhoodVertices from the GraphUtilities package:

Needs["GraphUtilities"]
NeighborhoodVertices[gg, 1, 1] // AbsoluteTiming


{0.017248, {1, 2, 11, 101, 1001}}

I'm working with large graphs that I need to manipulate quickly for several interactive information visualization tools. Any tips on why NeighborhoodGraph is so slow here and how to best use the new Graph package when speed is an issue?

-
I had this problem myself recently. I have no idea about an answer. I ended up using NeighborhoodVertices. Just replaced it with VertexComponents. Thanks – Cameron Murray Nov 13 '12 at 11:17

The issue is that NeighborhoodGraph is attempting to infer the layout of the original GridGraph. The layout algorithm for the parent graph is responsible for the slowness. At the cost of loosing the layout information this can be sped-up:

In[1]:= gg = GridGraph[{10, 10, 10, 10}, GraphLayout -> None];

In[2]:= VertexList[NeighborhoodGraph[gg, 1, 1]] // AbsoluteTiming

Out[2]= {0.0199998, {1, 2, 11, 101, 1001}}


The GraphLayout -> None has the effect that Graph object is not automatically rendered:

In version 9 and later, the simpler

NeighborhoodGraph[g, n, GraphLayout -> None]


form can be used for much faster neighbourhood graph computations.

-
Why does NeighbourhoodGraph need to invoke the layout algorithm? Computing the layout is not necessary if the graph is never shown (like here) ... Is this behaviour intentional or is this a bug? – Szabolcs Nov 14 '12 at 14:56
@Szabolcs It is so that NeighborhoodGraph could be used with HighlightGraph, e.g. gr = GridGraph[{3, 3, 3, 3}]; HighlightGraph[gr, NeighborhoodGraph[gr, 1, 1]]. – Sasha Nov 14 '12 at 15:28
In the meantime R.M. told me in the chatroom that NeighborhoodGraph preserves layout information (original vertex coordinates), which is useful sometimes. This information isn't really necessary for HighlightGraph though, for example HighlightGraph[g, Subgraph[g, VertexList@NeighborhoodGraph[g, 1]]] works even though Subgraph doesn't seem to preserve the original vertex coordinates. – Szabolcs Nov 14 '12 at 15:33
Maybe in a future version NeighborhoodGraph[g, 1, GraphLayout -> None] could be made to not compute the layout of g to make it simpler to keep a good performance and still use NeighborhoodGraph? I can't wait to see how Graph was improved in v9 :-) – Szabolcs Nov 14 '12 at 15:38
A question: do you know why SetOptions[NeighborhoodGraph, GraphLayout -> None] doesn't do what one would expect it to? NeighborhoodGraph is still slow unless I pass the GraphLayout -> None with each call. – Szabolcs Jan 20 '13 at 1:27

In my Boggle answer, I used a custom function to get the adjacent nodes for a vertex directly from the adjacency matrix . Not only is this much faster than using NeighborhoodGraph, it also gives you the adjacent nodes for all the nodes at once, so subsequent calls are instantaneous (you only need to index it). Here's the solution:

gg = GridGraph[{10, 10, 10, 10}];
Map[Last, SplitBy[list, First], {2}]]; // AbsoluteTiming
(* {0.138181, Null} *)


In comparison, NeighborhoodGraph takes around 3.38 seconds for each vertex! To get the adjacent nodes for a vertex $v$, simply take the $v$th part of adjNodes (these are instantaneous):

adjNodes[[2]]
(* {1, 3, 12, 102, 1002} *)


You can verify that you get the same result as Rest@VertexList@NeighborhoodGraph[gg, 8764, 1]`. This approach is very useful when you have a single large graph and you need to navigate it repeatedly.