# 4.5 The Notion of Dimension

In traditional geometry, a basic feature of any continuous space is its dimension. And we have seen that at least in certain cases we can characterize the limiting behavior of our models in terms of the emergence of recognizable geometrywith definite dimension. So this suggests that perhaps we might be able to use a notion of dimension to characterize the limiting behavior of our models even when we do not readily recognize traditional geometrical structure in them.

For standard continuous spaces it is straightforward to define dimension, normally in terms of the number of coordinates needed to specify a position. If we make a discrete approximation to a continuous space, say with a progressively finer grid, we can still identify dimension in terms of the number of coordinates on the grid. But now imagine we only have a connectivity graph for a grid. Can we deduce what dimension it corresponds to?

We might choose to draw the grids so they lay out according to coordinates, here in 1-, 2- and 3-dimensional Euclidean space:

GridGraph[{10}, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]
GridGraph[{10, 10}, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]
GridGraph[{5, 5, 5}, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]

But these are all the same graph, with the same connectivity information:

GridGraph[{10, 10}, GraphLayout -> #, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]] & /@ {"SpringElectricalEmbedding", "TutteEmbedding", "RadialEmbedding", "DiscreteSpiralEmbedding"}

So just from intrinsic information about a graphor, more accurately, from information about a sequence of larger and larger graphscan we deduce what dimension of space it might correspond to?

The procedure we will follow is straightforward (cf. [1:p479]). For any point X in the graph define Vr(X) to be the number of points in the graph that can be reached by going at most graph distance r. This can be thought of as the volume of a ball of radius r in the graph centered at X.

For a square grid, the region that defines Vr(X) for successive r starting at a point in the center is:

MakeBallPicture[g_, rmax_] := Module[{gg = UndirectedGraph[g], cg}, cg = GraphCenter[gg]; Table[HighlightGraph[gg, NeighborhoodGraph[gg, cg, r]], {r, 0, rmax}]]; Graph[#, Sequence[ ImageSize -> 60, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]] & /@ MakeBallPicture[GridGraph[{11, 11}], 7]

For an infinite grid we then have: For a 1D grid the corresponding result is:

MakeBallPicture[g_, rmax_] := Module[{gg = UndirectedGraph[g], cg}, cg = GraphCenter[gg]; Table[HighlightGraph[gg, NeighborhoodGraph[gg, cg, r]], {r, 0, rmax}]]; Graph[#, Sequence[ ImageSize -> 60, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]] & /@ MakeBallPicture[GridGraph[{11}], 7] And for a 3D grid it is:

MakeBallPicture[g_, rmax_] := Module[{gg = UndirectedGraph[g], cg}, cg = GraphCenter[gg]; Table[HighlightGraph[gg, NeighborhoodGraph[gg, cg, r]], {r, 0, rmax}]]; Graph[#, ImageSize -> 80, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]] & /@ MakeBallPicture[GridGraph[{7, 7, 7}], 5] In general, for a d-dimensional cubic grid (cf. [1:p1031]) the result is a terminating hypergeometric series (and the coefficient of zd in the expansion of (z+1)r/(z-1)r+1): But the important feature for us is that the leading termwhich is computable purely from connectivity information about the graphis proportional to rd.

What will happen for a graph that is less regular than a grid? Here is a graph made by random triangulation of a 2D region:

rgraph = MeshConnectivityGraph[ DiscretizeRegion[Rectangle[], MaxCellMeasure -> .002], VertexSize -> Tiny, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]

And once again, the number of points reached at graph distance r grows like r2:

rgraph = MeshConnectivityGraph[ DiscretizeRegion[Rectangle[], MaxCellMeasure -> .002], VertexSize -> Tiny, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]; Module[{cg}, cg = GraphCenter[rgraph]; Table[HighlightGraph[rgraph, NeighborhoodGraph[rgraph, cg, r], ImageSize -> 95], {r, 6}]]

In ordinary d-dimensional continuous Euclidean space, the volume of a ball is exactly And we should expect that if in some sense our graphs limit to d-dimensional space, then in correspondence with this, Vr should always show rd growth.

There are, however, many subtle issues. The firstimmediately evident in practiceis that if our graph is finite (like the grids above) then there are edge effects that prevent rd growth in Vr when the radius of the ball becomes comparable to the radius of the graph. The pictures below show what happens for a grid with side length 11, compared to an infinite grid, and the rd term on its own:

Table[With[{u = First[Values[ ResourceFunction["GraphNeighborhoodVolumes"][ GridGraph[Table[11, d]], GraphCenter[GridGraph[Table[11, d]]]]]]}, ListLinePlot[ Reverse@{Transpose[{Range[Length[u]] - 1, u}], Table[Evaluate[{r, FullSimplify@ FunctionExpand[ Binomial[r, d] Hypergeometric2F1[-d, 1 + r, 1 - d + r, -1]]}], {r, 0, Length[u] - 1}], Table[{r, 2^d/d! r^d}, {r, 0, Length[u - 1]}]}, Mesh -> All, Frame -> True, PlotRange -> {0, Max[u] + 1}, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"], If[d == 3, PlotLegends -> (Text[ Style[#, Directive[FontSize -> .85 Inherited, FontFamily -> "Source Serif Pro", GrayLevel[0.25]]]] & /@ {Style[Superscript["r", "d"], Italic], "infinite grid", "finite grid" }), PlotLegends -> None], Epilog -> Text[Style[Row[{Style["d", Italic], StringTemplate[" = ``"][d]}], Directive[FontSize -> 13, FontFamily -> "Source Serif Pro", GrayLevel[0.2]]], Scaled[{0, 1}], {-1.5, 1.3}]]], {d, 1, 3}]

One might imagine that edge effects would be avoided if one had a toroidal grid graph such as:

Graph[ResourceFunction["TorusGraph"][{11, 7}], VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]

But actually the results for Vr(X) for any point on a toroidal graph are exactly the same as those for the center point in an ordinary grid; it is just that now finite-size effects come from paths in the graph that wrap around the torus.

Still, so long as r is small compared to the radius of the graphbut large enough that we can see overall rd growthwe can potentially deduce an effective dimension from measurements of Vr.

In practice, a convenient way to assess the form of Vr, and to make estimates of dimension, is to compute log differences as a function of r: Here are results for the center points of grid graphs (or for any point in the analogous toroidal graphs):

griddim[d_, s_] := ResourceFunction["LogDifferences"][ N[First[Values[ ResourceFunction["GraphNeighborhoodVolumes"][ GridGraph[Table[s, d]], GraphCenter[GridGraph[Table[s, d]]]]]]]]; GraphicsRow[{ListLinePlot[{griddim[1, 51], Table[{r, 1}, {r, 26}]}, PlotStyle -> {ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"], Dotted}, PlotRange -> {0, 1.5}, Frame -> True], ListLinePlot[{griddim[2, 51], Table[{r, 2}, {r, 51}]}, PlotStyle -> {ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"], Dotted}, Frame -> True], ListLinePlot[{griddim[3, 21], Table[{r, 3}, {r, 30}]}, PlotStyle -> {ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"], Dotted}, Frame -> True]}, ImageSize -> Large]

The results are far from perfect. For small r one is sensitive to the detailed structure of the grid, and for large r to the finite overall size of the graph. But, for example, for a 2D grid graph, as the size of the graph is progressively increased, we see that there is an expanding region of values of r at which our estimate of dimension is accurate:

A notable feature of measuring dimension from the growth rate of Vr(X) is that the measurement is in some sense local: it starts from a particular position X. Of course, in looking at successively larger balls, Vr(X) will be sensitive to parts of the graph progressively further away from X. But still, the results can depend on the choice of X. And unless the graph is homogeneous (like our toroidal grids above), one will often want to average over at least a range of possible positions X. Here is an example of doing such averaging for a collection of starting points in the center of the random 2D graph above. The error bars indicate 1σ ranges in the distribution of values obtained from different points X.

rgraph = MeshConnectivityGraph[ DiscretizeRegion[Rectangle[], MaxCellMeasure -> .002], VertexSize -> Tiny, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"]]; ListLinePlot[ ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["GraphNeighborhoodVolumes"][rgraph, VertexList[NeighborhoodGraph[rgraph, GraphCenter[rgraph], 1]], Automatic]]]], Frame -> True, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]]

So far we have looked at graphs that approximate standard integer-dimensional spaces. But what about fractal spaces ? Let us consider a Sierpiński graph, and look at the growth of a ball in the graph:

Module[{cg, sier = IndexGraph[MeshConnectivityGraph[SierpinskiMesh, 0], VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]}, cg = First[GraphCenter[sier]]; Table[Labeled[ HighlightGraph[sier, NeighborhoodGraph[sier, cg, r], ImageSize -> 140], Text[Style[Row[{Style["r", Italic], StringTemplate[" = ``"][r]}], Directive[GrayLevel[.25], FontSize -> .85 Inherited, FontFamily -> "Source Serif Pro" ]]]], {r, 5, 20, 5}]]

Estimating dimension from Vr(X) averaged over all points we get (for graphs made from 6 and 7 recursive subdivisions):

GraphicsRow[ Table[Module[{sier = IndexGraph[MeshConnectivityGraph[SierpinskiMesh[ss], 0]], w}, w = ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["GraphNeighborhoodVolumes"][sier, All, Automatic]]]]; ListLinePlot[{w, Table[{r, Log[2, 3]}, {r, Length[w]}]}, PlotStyle -> {ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"], Dotted}, Frame -> True]], {ss, 6, 7}], ImageSize -> Large]

The dotted line indicates the standard Hausdorff dimension log2(3)1.58 for a Sierpiński triangle . And what the pictures suggest is that the growth rate of Vr approximates this value. But to get the exact value we see that in addition to everything else, we will need average estimates of dimension over different values of r.

In the end, therefore, we have quite a collection of limits to take. First, we need the overall size of our graph to be large. Second, we need the range of values of r for measuring Vr to be small compared to the size of the graph. Third, we need these values to be large relative to individual nodes in the graph, and to be large enough that we can readily measure the leading order growth of Vrand that this will be of the form rd. In addition, if the graph is not homogeneous we need to be averaging over a region X that is large compared to the size of inhomogeneities in the graph, but small compared to the values of r we will use in estimating the growth of Vr. And finally, as we have just seen, we may need to average over different ranges of r in estimating overall dimension.

If we have something like a grid graph, all of this will work out fine. But there are certainly cases where we can immediately tell that it will not work. Consider, for example, first the case of a complete graph, and second of a tree:

{CompleteGraph[20, Sequence[ VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]], TreePlot[KaryTree, Center, Sequence[ VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]]}

For a complete graph there is no way to have a range of r values “smaller than the radius of graph” from which to estimate a growth rate for Vr. For a tree, Vr grows exponentially rather than as a power of r, so our estimate of dimension Δ(r) will just continually increase with r:

ListLinePlot[ ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["GraphNeighborhoodVolumes"][ KaryTree, All, Automatic]]]], Frame -> True, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]]

But notwithstanding these issues, we can try applying our approach to the objects generated by our models. As constructed, these objects correspond to directed graphs or hypergraphs. But for our current purposes, we will ignore directedness in determining distance, effectively taking all elements in a particular k-ary relationregardless of their orderingto be at unit distance from each other.

As a first example, consider the 23 33 rule we discussed above that “knits” a simple grid:

ResourceFunction[ "WolframModel"][{{1, 2, 2}, {3, 1, 4}} -> {{2, 5, 2}, {2, 3, 5}, {4, 5, 5}}, {{0, 0, 0}, {0, 0, 0}}, 200, "FinalStatePlot"]

As we run the rule, the structure it produces gets larger, so it becomes easier to estimate the growth rate of Vr. The picture below shows Δ(r) (starting at the center point) computed after successively more steps. And we see that, as expected, the dimension estimate appears to converge to value 2:

CenteredDimensionEstimateList[g_Graph] := ResourceFunction["LogDifferences"][ N[First[Values[ ResourceFunction["GraphNeighborhoodVolumes"][g, GraphCenter[g]]]]]]; Show[ListLinePlot[ Table[CenteredDimensionEstimateList[ UndirectedGraph[ ResourceFunction["HypergraphToGraph"][ ResourceFunction[ "WolframModel"][{{1, 2, 2}, {3, 1, 4}} -> {{2, 5, 2}, {2, 3, 5}, {4, 5, 5}}, {{0, 0, 0}, {0, 0, 0}}, t, "FinalState"]]]], {t, 500, 2500, 500}], Frame -> True, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]], Plot[2, {r, 0, 50}, PlotStyle -> Dotted]]

It is worth mentioning that if we did not compute Vr(X) by starting at the center point, but instead averaged over all points, we would get a less useful result, dominated by edge effects:

HypergraphDimensionEstimateList[hg_] := ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["HypergraphNeighborhoodVolumes"][hg, All, Automatic]]]]; Show[ListLinePlot[ Table[HypergraphDimensionEstimateList[ ResourceFunction[ "WolframModel"][{{1, 2, 2}, {3, 1, 4}} -> {{2, 5, 2}, {2, 3, 5}, {4, 5, 5}}, {{0, 0, 0}, {0, 0, 0}}, t, "FinalState"]], {t, 500, 2500, 500}], Frame -> True, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]], Plot[2, {r, 0, 50}, PlotStyle -> Dotted]]

As a second example, consider the 23 33 rule that slowly generates a somewhat complex kind of surface:

ResourceFunction[ "WolframModel"][{{1, 1, 2}, {1, 3, 4}} -> {{4, 4, 5}, {5, 4, 2}, {3, 2, 5}}, {{0, 0, 0}, {0, 0, 0}}, 500, "FinalStatePlot"]

As we run this longer, we see what appears to be increasingly close approximation to dimension 2, reflecting the fact that even though we can best draw this object embedded in 3D space, its intrinsic surface is two-dimensional (though, as we will discuss later, it also shows the effects of curvature):

HypergraphDimensionEstimateList[hg_] := ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["HypergraphNeighborhoodVolumes"][hg, All, Automatic]]]]; Show[ListLinePlot[ Table[HypergraphDimensionEstimateList[ ResourceFunction[ "WolframModel"][{{1, 1, 2}, {1, 3, 4}} -> {{4, 4, 5}, {5, 4, 2}, {3, 2, 5}}, {{0, 0, 0}, {0, 0, 0}}, t, "FinalState"]], {t, 500, 2500, 500}], Frame -> True, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]], Plot[2, {r, 0, 50}, PlotStyle -> Dotted]]

The successive dimension estimates shown above are spaced by 500 steps in the evolution of the rule. As another example, consider the 2312 4342 rule, in which geometry emerges rapidly through a process of subdivision:

ResourceFunction[ "WolframModel"][{{1, 2, 3}, {4, 5, 6}, {1, 4}} -> {{2, 7, 8}, {3, 9, 10}, {5, 11, 12}, {6, 13, 14}, {13, 8}, {7, 10}, {9, 12}, {11, 14}}, {{0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0}}, 9, "FinalStatePlot"]

These are dimension estimates for all of the first 10 steps in the evolution of this rule:

HypergraphDimensionEstimateList[hg_] := ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["HypergraphNeighborhoodVolumes"][hg, All, Automatic]]]]; Show[ListLinePlot[ Table[HypergraphDimensionEstimateList[ ResourceFunction[ "WolframModel"][{{1, 2, 3}, {4, 5, 6}, {1, 4}} -> {{2, 7, 8}, {3, 9, 10}, {5, 11, 12}, {6, 13, 14}, {13, 8}, {7, 10}, {9, 12}, {11, 14}}, {{0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0}}, t, "FinalState"]], {t, 1, 10}], Frame -> True, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]], Plot[2, {r, 0, 100}, PlotStyle -> Dotted]]

We can also validate our approach by looking at rules that generate obviously nested structures. An example is the 22 42 rule that produces:

ResourceFunction[ "WolframModel"][{{1, 2}, {3, 2}} -> {{2, 4}, {2, 4}, {4, 1}, {3, 4}}, {{0, 0}, {0, 0}, {0, 0}}, 12, "FinalStatePlot"]

The results for each of the first 15 steps show good correspondence to dimension log2(3)1.58:

HypergraphDimensionEstimateList[hg_] := ResourceFunction["LogDifferences"][ MeanAround /@ Transpose[ Values[ResourceFunction["HypergraphNeighborhoodVolumes"][hg, All, Automatic]]]]; Show[ListLinePlot[ Table[HypergraphDimensionEstimateList[ ResourceFunction[ "WolframModel"][{{1, 2}, {3, 2}} -> {{2, 4}, {2, 4}, {4, 1}, {3, 4}}, {{0, 0}, {0, 0}, {0, 0}}, t, "FinalState"]], {t, 1, 15}], Frame -> True, PlotRange -> {0, Automatic}, PlotStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "GenericLinePlot", "PlotStyles"]], Plot[Log[2, 3], {r, 0, 150}, PlotStyle -> Dotted]]