Original answer is below. Here's something different. The virtue of this is that it is simple to implement in Mathematica.
Let's make a test graph. Note that below we will never make use of the special vertex or edge ordering that the GridGraph
function produces. The same method will for any graph that is a regular 2D lattice, regardless of how the vertices are named or ordered.
g = GridGraph[{5,6}];
There are 4 corners of the lattice, all with degree 2:
{c1, c2, c3, c4} = Pick[VertexList[g], VertexDegree[g], 2];
Pick two into the variables c1
and c2
, in such a way that they are not diagonally opposite. This can be ensured by making sure that their distance is not the highest:
If[GraphDistance[g, c1, c2] > GraphDistance[g, c1, c3], c2 = c3]
Compute vertex distances from both corners:
a = GraphDistance[g, c1];
b = GraphDistance[g, c2];
Using the sum and differences of these distances as vertex coordinates gives a nice lattice embedding:
SetProperty[g, VertexCoordinates -> Transpose[{a - b, a + b}]]
We can also use these coordinates as indices into a matrix. We just need to make sure that they start at 1.
coord = (1 + Transpose[{a - b, a + b}])/2;
min = Min /@ Transpose[coord];
coord = # - min & /@ coord + 1;
MatrixForm@SparseArray@Thread[coord -> VertexList[g]]
Wy does this work?
If we think about the distance of any vertex from the two top corners, it will be clear that:
Moving one step to the left in the lattice will decrease the distance from the top left corner by one and increase the distance from the top right corner by 1. The sum of distances doesn't change.
Moving one step down increases both distances: the difference of distances doesn't change.
Old answer
I don't have time to implement this, unfortunately, but here's an idea for an algorithm:
We can categorize nodes in the graphs based on their degree. Corner vertices have degree 2, edge vertices have degree 3 and inner vertices have degree 4.
The algorithm:
- Select a corner
- Select a neighbour of the corner. This will be on the edge of the lattice, i.e. will have degree 3. Mark this as the "current node".
- Take a yet unvisited degree 3 neighbour of the current node and make it the next current node. This will also be on the edge.
- Repeat until we reach the next corner. Now remove the whole row of nodes in the lattice that we have visited.
- Continue traversing rows like this until nothing is left.
Of course this requires special checks for handling the last row, etc. It may be practical to remove each node from the lattice as we visit it, to avoid having to keep track of visited nodes.
A more interesting case would be a periodic lattice, which has no corners or edges. This can probably be handled by selecting any starting node, then selecting two neighbours which have a different common neighbour than the starting node. This gives us an oriented unit cell of the lattice. Continue identifying unit cells and moving in the same direction until we arrive back to the original. Then take the next row of unit cells, and so on.
I hope this is clear. Anyone is welcome to post an implementation, as I won't have time to do it.
VertexLabels -> "Index"
? $\endgroup$