Education
Faster than Light in Our Model of Physics: Some Preliminary Thoughts
When the NASA Innovative Advanced Concepts Program asked me to keynote their annual conference, I thought it would be a good excuse to spend some time on a question that I’ve always thought would be interesting to explore…
Can You Build a Warp Drive?
“So you think you have a fundamental theory of physics. Well, then tell us if warp drive is possible!” Despite the hopes and assumptions of science fiction, real physics has for at least a century almost universally assumed that no genuine effect can ever propagate through physical space any faster than light. But is this actually true? We’re now in a position to analyze this in the context of our model for fundamental physics. And I’ll say at the outset that it’s a subtle and complicated question, and I don’t know the full answer yet.
But I increasingly suspect that going faster than light is not a physical impossibility; instead, in a sense, doing it is “just” an engineering problem. But it may well be an irreducibly hard engineering problem. And one that can’t be solved with the computational resources available to us in our universe. But it’s also conceivable that there may be some clever “engineering solution”, as there have been to so many seemingly insuperable engineering problems in the past. And that in fact there is a way to “move through space” faster than light.
It’s a little tricky even to define what it means to “go faster than light”. Do we allow an existing “space tunnel” (like the wormholes of general relativity)? Perhaps a space tunnel that has been there since the beginning of the universe. Or even if no space tunnel already exists, do we allow the possibility of building one—that we can then travel through? I’ll discuss these possibilities later. But the most dramatic possibility is that even if one’s going where “no one has gone before”, it might still be possible to traverse space faster than light to get there.
To give a preview of why doing this might devolve into an “engineering problem”, let’s consider a loose (but, in the end, not quite so loose) analogy. Imagine you’ve got molecules of gas in a room, all bouncing around and colliding with each other. Now imagine there’s a special molecule—or even a tiny speck of dust or a virus particle—somewhere in the room. Normally the special molecule will be buffeted by the molecules in the air, and will move in some kind of random walk, gradually diffusing across the room. But imagine that the special molecule somehow knows enough about the motion of the air molecules that it can compute exactly where to go to avoid being buffeted. Then that special molecule can travel much faster than diffusion—and effectively make a beeline from one side of the room to the other.
Of course this requires more knowledge and more computation than we currently imagine something like a molecule can muster (though it’s not clear this is true when we start thinking about explicitly constructing moleculescale computers). But the point is that the limit on the speed of the molecule is less a question of what’s physically possible, and more a question of what’s “engineerable”.
And so, I suspect, it is with space, and motion through space. Like our room full of air molecules, space in our theory of physics has a complex structure with many component parts that act in seemingly (but not actually) random ways. And in our theory the question of whether we can “move through space” faster than light can then be thought of as becoming a question of whether there can exist a “space demon” that can find ways to do computations fast enough to be able to successfully “hack space”.
But before we can discuss this further, we have to talk about just what space—and time—are in our models.
The Structure of Space and the Nature of Time
In standard physics, space (and the “spacetime continuum”) is just a background on which everything exists. Mathematically, it’s thought of as a manifold, in which every possible position can ultimately be labeled by 3 coordinate values. In our model, space is different. It’s not just a background; it’s got definite, intrinsic structure. And in fact everything in the universe is ultimately defined by that structure; in fact, at some level, everything is just “made of space”.
We might think of something like water as being a continuous fluid. But we know that at a small scale it’s actually made of discrete molecules. And so it is, I suspect, with space. At a small enough scale, there are actually discrete “atoms of space”—and only on a large scale does space appear to be continuous.
In our model, the “atoms of space” correspond to abstract elements whose only property is their relation to other abstract elements. Mathematically the structure can be thought of as a hypergraph, where the atoms of space are nodes, which are related by hyperedges to other nodes. On a very small scale we might have for example:
✕
Graph3D[Rule @@@ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 5, "FinalState"], GraphLayout > "SpringElectricalEmbedding"] 
On a slightly larger scale we might have:
✕
Graph3D[Rule @@@ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 12, "FinalState"]] 
And in our actual universe we might have a hypergraph with perhaps 10^{400} nodes.
How does a giant hypergraph behave like continuous space? In a case like this we can see that the nodes can be thought of as forming a 2D grid on a (curved) surface:
✕
ResourceFunction[ "WolframModel"][{{1, 2, 3}, {4, 2, 5}} > {{6, 3, 1}, {3, 6, 4}, {1, 2, 6}}, {{0, 0, 0}, {0, 0, 0}}, 1000, "FinalStatePlot"] 
There’s nothing intrinsic about our model of space that determines the effective dimensionality it will have. These are all perfectly good possible (hyper)graphs, but on a large scale they behave like space in different numbers of dimensions:
✕
Table[GridGraph[Table[10, n]], {n, 1, 3}] 
It’s convenient to introduce the notion of a “geodesic ball”: the region in a (hyper)graph that one reaches by following at most r connections in the (hyper)graph. A key fact is that in a (hyper)graph that limits to ddimensional space, the number of nodes in the geodesic ball grows like r^{d}. In a curved space (say, on the surface of a sphere) there’s a correction to r^{d}, proportional to the curvature of the space.
The full story is quite long, but ultimately what happens is that—much as we can derive the properties of a fluid from the largescale aggregate dynamics of lots of discrete molecules—so we can derive the properties of space from the largescale aggregate dynamics of lots of nodes in our hypergraphs. And—excitingly enough—it seems that we get exactly Einstein’s equations from general relativity.
OK, so if space is a collection of elements laid out in a “spatial hypergraph”, what is time? Unlike in standard physics, it’s something initially very different. It’s a reflection of the process of computation by which the spatial hypergraph is progressively updated.
Let’s say our underlying rule for updating the hypergraph is:
✕
RulePlot[ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} > {{x, y}, {x, w}, {y, w}, {z, w}}]] 
Here’s a representation of the results of a sequence of updates according to this:
✕
Flatten[With[{eo = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}, {{0, 0}, {0, 0}}, 4]}, TakeList[eo["EventsStatesPlotsList", ImageSize > Tiny], eo["GenerationEventsCountList", "IncludeBoundaryEvents" > "Initial"]]]] 
Going further we’ll get for example:
✕
ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}, {{1, 1}, {1, 1}}, 10]["StatesPlotsList", "MaxImageSize" > 100] 
But there’s a crucial point here. The underlying rule just defines how a local piece of hypergraph that has a particular form should be updated. If there are several pieces of hypergraph that have that form, it doesn’t say anything about which of them should be updated first. But once we’ve done a particular update, that can affect subsequent updates—and in general there’s a whole “causal graph” of causal relationships between updates.
We can see what’s going on a little more easily if instead of using spatial hypergraphs we just use strings of characters. Here we’re updating a string by repeatedly applying the (“sorting”) rule BA → AB:
✕
evo = (SeedRandom[2424]; ResourceFunction[ "SubstitutionSystemCausalEvolution"][{"BA" > "AB"}, "BBAAAABAABBABBBBBAAA", 10, {"Random", 4}]); ResourceFunction["SubstitutionSystemCausalPlot"][evo, EventLabels > False, CellLabels > True, CausalGraph > False] 
The yellow boxes indicate “updating events”, and we can join them by a causal graph that represents which event affects which other ones:
✕
evo = (SeedRandom[2424]; ResourceFunction[ "SubstitutionSystemCausalEvolution"][{"BA" > "AB"}, "BBAAAABAABBABBBBBAAA", 10, {"Random", 4}]); ResourceFunction["SubstitutionSystemCausalPlot"][evo, EventLabels > False, CellLabels > False, CausalGraph > True] 
If we’re an observer inside this system, all we can directly tell is what events are occurring, and how they’re causally connected. But to set up a description of what’s going on, it’s convenient to be able to talk about certain events happening “at a certain time”, and others happening later. Or, in other words, we want to define some kind of “simultaneity surfaces”—or a “reference frame”.
Here are two choices for how to do this
✕
CloudGet["https://wolfr.am/KVkTxvC5"]; CloudGet["https://wolfr.am/KVl97Tf4"]; Show[regularCausalGraphPlot[10, {1, 0}, {#, 0.0}, lorentz[0]], ImageSize > 330] & /@ {0., .3} 
where the second one can be reinterpreted as:
✕
CloudGet["https://wolfr.am/KVkTxvC5"]; CloudGet["https://wolfr.am/KVl97Tf4"]; regularCausalGraphPlot[10, {1, 0}, {0.3, 0.0}, lorentz[0.3]] 
And, yes, this can be thought of as corresponding to a reference frame with a different speed, just like in standard special relativity. But now there’s a crucial point. The particular rule we’ve used here is an example of one with the property of causal invariance—which means that it doesn’t matter “at what time” we do a particular update; we’ll always get the same causal graph. And this is why—even though space and time start out so differently in our models—we end up being able to derive the fact that they follow special relativity.
Given a reference frame, we can always “reconstruct” a view of the behavior of the system from the causal graph. In the cases shown here we’d get:
✕
CloudGet["https://wolfr.am/LbaDFVSn"]; GraphicsRow[ Show[ResourceFunction["SubstitutionSystemCausalPlot"][ boostedEvolution[ ResourceFunction[ "SubstitutionSystemCausalEvolution"][{"BA" > "AB"}, StringRepeat["BA", 10], 5], #], EventLabels > False, CellLabels > True, CausalGraph > False], ImageSize > {250, Automatic}] & /@ {0., 0.3}, Alignment > Top] 
And the fact that the system seems to “take longer to do its thing” in the second reference frame is precisely a reflection of relativistic time dilation in that frame.
Just as with strings, we can also draw causal graphs to represent the causal relationships between updating events in spatial hypergraphs. Here’s an example of what we get for the rule shown above:
✕
ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 7]["LayeredCausalGraph", AspectRatio > 1/2] 
And once again we can set up reference frames to define what events we want to consider “simultaneous”. The only fundamental constraint on our reference frames is that in each slice of the “foliation” that defines the reference frame there can never be two events in which one follows from the other. Or, in the language of relativity, no events in a given slice can be timelike separated; instead, all of them must be spacelike separated, so that the slice defines a purely spacelike hypersurface.
In drawing a causal graph like the one above, we’re picking a particular collection of relative orderings of different possible updating events in the spatial hypergraph. But why one choice and not another? A key feature of our models is that actually we can think of all possible orderings as being done, or said, differently, we can construct a whole multiway graph of possibilities. Here’s what the multiway graph looks like for the string system above:
✕
LayeredGraphPlot[ ResourceFunction["MultiwaySystem"][{"BA" > "AB"}, "BBABBAA", 8, "StatesGraph"], AspectRatio > 1] 
Each node in this multiway graph represents a complete state of our system (in this case, a string), and a path through the multiway system corresponds to a possible history of the system, with a particular corresponding causal graph.
But now there’s an important connection with physics: the fact that we get a multiway graph makes quantum mechanics inevitable in our models. And it turns out that just like we can use reference frames to make sense of the evolution of our systems in space and time, so also we can use “quantum observation frames” to make sense of the time evolution of multiway graphs. But now the analog of space is what we call “branchial space”: in effect a space of possible quantum states, with the connections between states defined by their relationship on branches in the multiway system.
And much as we can define a spatial hypergraph representing relationships between “points in space”, so we can define a branchial graph that represents relationships (or “entanglements”) between quantum states, in branchial space:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{"LayeredGraphPlot", "[", RowBox[{ RowBox[{"Graph", "[", RowBox[{ RowBox[{"ResourceFunction", "[", ""<MultiwaySystem>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{""<A>"", "[Rule]", ""<AB>""}], ",", RowBox[{""<B>"", "[Rule]", ""<A>""}]}], "}"}], ",", ""<A>"", ",", "5", ",", ""<EvolutionGraph>""}], "]"}], "]"}], ",", RowBox[{"Epilog", "[Rule]", RowBox[{"{", RowBox[{ RowBox[{ RowBox[{ "ResourceFunction", "[", ""<WolframPhysicsProjectStyleData>"", "]"}], "[", RowBox[{""<BranchialGraph>"", ",", ""<EdgeStyle>""}], "]"}], ",", RowBox[{"AbsoluteThickness", "[", "1.5", "]"}], ",", RowBox[{"Table", "[", RowBox[{ RowBox[{"Line", "[", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"", "10"}], ",", "i"}], "}"}], ",", RowBox[{"{", RowBox[{"9", ",", "i"}], "}"}]}], "}"}], "]"}], ",", RowBox[{"{", RowBox[{"i", ",", ".4", ",", "5", ",", "1.05"}], "}"}]}], "]"}]}], "}"}]}]}], "]"}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"ResourceFunction", "[", ""<MultiwaySystem>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{""<A>"", "[Rule]", ""<AB>""}], ",", RowBox[{""<B>"", "[Rule]", ""<A>""}]}], "}"}], ",", ""<A>"", ",", "5", ",", ""<BranchialGraph>""}], "]"}]], "Input"] }, Open ]] 
I won’t go into the details here, but one of the beautiful things in our models is that just as we can derive the Einstein equations as a largescale limiting description of the behavior of our spatial hypergraphs, so also we can figure out the largescale limiting behavior for multiway systems—and it seems that we get the Feynman path integral for quantum mechanics!
By the way, since we’re talking about faster than light and motion in space, it’s worth mentioning that there’s also a notion of motion in branchial space. And just like we have the speed of light c that defines some kind of limit on how fast we can explore physical space, so also we have a maximal entanglement rate ζ that defines a limit on how fast we can explore (and thus “entangle”) different quantum states in branchial space. And just as we can ask about “faster than c”, we can also talk about “faster than ζ”. But before we get to that, we’ve got a lot of other things to discuss.
Can We Make Tunnels in Space?
Traditional general relativity describes space as a continuous manifold that evolves according to certain partial differential equations. But our models talk about what’s underneath that, and what space actually seems to be made of. And while in appropriate limits they reproduce what general relativity says, they also imply all sorts of new and different phenomena.
Imagine that the hypergraph that represents space has the form of a simple 2D grid:
✕
GridGraph[{15, 15}, EdgeStyle > ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"], VertexStyle > ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"]] 
In the limit this will be like 2D Euclidean space. But now suppose we add some extra “longrange threads” to the graph:
✕
SeedRandom[243234]; With[{g = GridGraph[{20, 20}]}, EdgeAdd[g, UndirectedEdge @@@ Select[Table[RandomInteger[{1, VertexCount[g]}, 2], 10], GraphDistance[g, #[[1]], #[[2]]] > 8 &], EdgeStyle > ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "EdgeLineStyle"], VertexStyle > ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph", "VertexStyle"]]] 
Here’s a different rendering of the same graph:
✕
Graph3D[EdgeList[%], EdgeStyle > ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph3D", "EdgeLineStyle"], VertexStyle > ResourceFunction["WolframPhysicsProjectStyleData"]["SpatialGraph3D", "VertexStyle"]] 
Now let’s ask about distances on this graph. Some nodes on the graph will have distances that are just like what one would expect in ordinary 2D space. But some will be “anomalously close”, because one will be able to get from one to another not by going “all the way through 2D space” but by taking a shortcut along one of the longrange threads.
Let’s say that we’re able to move around so that at every elementary interval of time we traverse a single connection in the graph. Then if our view of “what space is like” is based on the general structure of the graph (ignoring the longrange threads) we’ll come to some conclusion about how far we can go in a certain time—and what the maximum speed is at which we can “go through space”. But then what happens if we encounter one of the longrange threads? If we go through it we’ll be able to get from one “place in space” to another much faster than would be implied by the maximum speed we deduced from looking at “ordinary space”.
In a graph, there are many ways to end up having “longrange threads”—and we can think of these as defining various kinds of “space tunnels” that provide ways to get around in space evading usual speedoflight constraints. We can imagine both persistent space tunnels that could be repeatedly used, and spontaneous or “justintime” ones that exist only transiently. But—needless to say—there is all sorts of subtlety around the notion of space tunnels. If a tunnel is a pattern in a graph, what actually happens when something “goes through it”? And if a tunnel didn’t always exist, how does it get formed?
Space tunnels are a fairly general concept that can be defined on graphs or hypergraphs. But there’s at least a special case of them that can be defined even in standard general relativity: wormholes. General relativity describes space as a continuum—a manifold—in which there’s no way to have “just a few longrange threads”. The best one can do is to imagine that there’s a kind of “handle in space”, that provides an alternative path from one part of space to another:
How would such a nonsimplyconnected manifold form? Perhaps it’s a bit like the gastrulation that happens in embryonic development. But mathematically one can’t continuously change the topology of something continuous; there has to at least be some kind of singularity. In general relativity it’s been tricky to see how this could work. But of course in our models there’s not the same kind of constraint, because one doesn’t have to “rearrange a whole continuum”; one can do something more like “growing a handle one thread at a time”.
Here’s an example where one can see something a bit like this happening. We’re using the rule:
✕
RulePlot[ResourceFunction[ "WolframModel"][{{1, 2, 3}, {1, 4, 5}} > {{3, 3, 6}, {6, 6, 5}, {4, 5, 6}}]] 
And what it does is effectively to “knit handles” that provide “shortcuts” between “separated” points in patches of what limits to 2D Euclidean space:
✕
Labeled[ResourceFunction[ "WolframModel"][{{1, 2, 3}, {1, 4, 5}} > {{3, 3, 6}, {6, 6, 5}, {4, 5, 6}}, {{0, 0, 0}, {0, 0, 0}}, #, "FinalStatePlot"], Text[#]] & /@ {0, 5, 10, 50, 100, 500, 1000} 
In our models—free from the constraints of continuity—space can have all sorts of exotic forms. First of all, there’s no constraint that space has to have an integer number of dimension (say 3). Dimension is just defined by the asymptotic growth rates of balls, and can have any value. Like here’s a case that approximates 2.3dimensional space:
✕
ResourceFunction[ "WolframModel"][{{{1, 2, 3}, {2, 4, 5}} > {{6, 7, 2}, {5, 7, 8}, {4, 2, 8}, {9, 3, 5}}}, {{0, 0, 0}, {0, 0, 0}}, 20, "FinalStatePlot"] 
It’s worth noting that although it’s perfectly possibly to define distance—and, in the limit, lots of other geometric concepts—on a graph like this, one doesn’t get to say that nodes are at positions defined by particular sets of coordinates, as one would in integerdimensional space.
With a manifold, one basically has to pick a certain (integer) dimension, then stick to it. In our models, dimension can effectively become a dynamical variable, that can change with position (and time). So in our models one possible form of “space tunnel” is a region of space with higher or lower dimension. (Our derivation of general relativity is based on assuming that space has a limiting finite dimension, then asking what curvature and other properties it must have; the derivation is in a sense blind to differentdimensional space tunnels.)
It’s worth noting that both lower and higherdimensional space tunnels can be interesting in terms of “getting places quickly”. Lowerdimensional space tunnels (such as bigger versions of the 1D longrange threads in the 2D grid above) potentially connect some specific sparse set of “distant” points. Higherdimensional space tunnels (which in the infinitedimensional limit can be trees) are more like “switching stations” that make many points on their boundaries closer.
Negative Mass, Wormholes, etc.
Let’s say we’ve somehow managed to get a space tunnel. What will happen to it? Traditional general relativity suggests that it’s pretty hard to maintain a wormhole under the evolution of space implied by Einstein’s equations. A wormhole is in effect defined by geodesic paths coming together when they enter the wormhole and diverging again when they exit. In general relativity the presence of mass makes geodesics converge; that’s the “attraction due to gravity”. But what could make the geodesics diverge again? Basically one needs some kind of gravitational repulsion. And the only obvious way to get this in general relativity is to introduce negative mass.
Normally mass is assumed to be a positive quantity. But, for example, dark energy effectively has to have negative mass. And actually there are several mechanisms in traditional physics that effectively lead to negative mass. All of them revolve around the question of where one sets the zero to be. Normally one sets things up so that one can say that “the vacuum” has zero energy (and mass). But actually—even in traditional physics—there’s lots that’s supposed to be going on in “the vacuum”. For example, there’s supposed to be a constant intensity of the Higgs field, that interacts with all massive particles and has the effect of giving them mass. And there are supposed to be vacuum fluctuations associated with all quantum fields, each leading (at least in standard quantum field theory) to an infinite energy density.
But if these things exist everywhere in the universe, then (at least for most purposes) we can just set our zero of energy to include them. So then if there’s anything that can reduce their effects, we’ll effectively see negative mass. And one example of where this can in some sense happen is the Casimir effect. Imagine that instead of having an infinite vacuum, we just have vacuum inside a box. Having the box cuts out some of the possible vacuum fluctuations of quantum fields (basically modes with wavelengths larger than the size of the box)—and so in some sense leads to negative energy density inside the box (at least relative to outside). And, yes, the effect is observable with metal boxes, etc. But what becomes of the Casimir effects in a purely spacetime or gravitational setting isn’t clear.
(This leads to a personal anecdote. Back in 1981 I wrote two papers about the Casimir effect with Jan Ambjørn, titled Properties of the Vacuum: 1. Mechanical and …: 2. Electrodynamic. We had planned a “…: 3. Gravitational” but never wrote it, and now I’m really curious what the results would have been. By the way, our paper #1 computed Casimir effects for boxes of different shapes, and had the surprising implication that by changing shapes in a cycle it would in principle be possible to continuously “mine” energy from the vacuum. This was later suggested as a method for interstellar propulsion, but to make it work requires an infinitely impermeable box, which doesn’t seem physically constructible, except maybe using gravitational effects and event horizons… but we never wrote paper #3 to figure that out….)
In traditional physics there’s been a conflict between what the vacuum is like according to quantum field theory (with infinite energy density from vacuum fluctuations, etc.) and what the vacuum is assumed to be like in general relativity (effectively zero energy density). In our models there isn’t the same kind of conflict, but “the vacuum” is something with even more structure.
In particular, in our models, space isn’t some separate thing that exists; it is just a consequence of the largescale structure of the spatial hypergraph. And any matter, particles, quantum fields, etc. that exist “in space” must also be features of this same hypergraph. Things like vacuum fluctuations aren’t something that happens in space; they are an integral part of the formation of space itself.
By the way, it’s important to note that in our models the hypergraph isn’t something static—and it’s in the end knitted together only through actual update events that occur. And the energy of some region of the hypergraph is directly related to the amount of updating activity in that region (or, more accurately, to the flux of causal edges through that portion of spacelike hypersurfaces).
So what does this mean for negative mass in our models? Well, if there was a region of the hypergraph where there was somehow less activity, it would have negative energy relative to the zero defined by the “normal vacuum”. It’s tempting to call whatever might reduce activity in the hypergraph a “vacuum cleaner”. And, no, we don’t know if vacuum cleaners can exist. But if they do, then there’s a fairly direct path to seeing how wormholes can be maintained (basically because geodesics almost by definition diverge wherever a vacuum cleaner has operated).
By the way, while a largescale wormholelike structure presumably requires negative mass, vacuum cleaners, etc., and other space tunnel structures may not have the same requirements. By their very construction, they tend to operate outside the regime described by general relativity and Einstein’s equations. So things like the standard singularity theorems of general relativity can’t be expected to apply. And instead there doesn’t seem to be any choice but to analyze them directly in the context of our models.
One might think: given a particular space tunnel configuration, why not just run a simulation of it, and see what happens? The problem is computational irreducibility. Yes, the simulation might show that the configuration is stable for a million or a billion steps. But that might still be far, far away from humanlevel timescales. And there may be no way to determine what the outcome for a given number of steps will be except in effect by doing that irreducible amount of computational work—so that if, for example, we want to find out the limiting result after an infinite time, that’ll in general require an infinite amount of computational work, and thus effectively be undecidable.
Or, put another way, even if we can successfully “engineer” a space tunnel, there may be no systematic way to guarantee that it’ll “stay up”; it may require an infinite sequence of “engineering tweaks” to keep it going, and eventually it may not be possible to keep it going. But before that, of course, we have to figure out how to construct a space tunnel in the first place…
It Doesn’t Mean Time Travel
In ordinary general relativity one tends to think of everything in terms of spacetime. So if a wormhole connects two different places, one assumes they are places in spacetime. Or, in other words, a wormhole can allow shortcuts between both different parts of space, and different parts of time. But with a shortcut between different parts of time one can potentially have time travel.
More specifically, one can have a situation where the future of something affects its past: in other words there is a causal connection from the future to the past. At some level this isn’t particularly strange. In any system that behaves in a perfectly periodic way one can think of the future as leading to a repetition of the past. But of course it’s not a future that one can freely determine; it’s just a future that’s completely determined by the periodic behavior.
How all this works is rather complicated to see in the standard mathematical treatment of general relativity, although in the end what presumably happens is that in the presence of wormholes the only consistent solutions to the equations are ones for which past and future are locked together with something like purely periodic behavior.
Still, in traditional physics there’s a certain sense that “time is just a coordinate”, so there’s the potential for “motion in time” just like we have motion in space. In our models, however, things work quite differently. Because now space and time are not the same kind of thing at all. Space is defined by the structure of the spatial hypergraph. But time is defined by the computational process of applying updates. And that computational process undoubtedly shows computational irreducibility.
So while we may go backwards and forwards in space, exploring different parts of the spatial hypergraph, the progress of time is associated with the progressive performance of irreducible computation by the universe. One can compute what will happen (or, with certain restrictions, what has happened), but one can only do so effectively by following the actual steps of it happening; one can’t somehow separately “move through it” to see what happens or has happened.
But in our models the whole causality of events is completely tracked, and is represented by the causal graph. And in fact each connection in the causal graph can be thought of as a representation of the very smallest unit of progression in time.
So now let’s look at a causal graph again:
✕
ResourceFunction[ "WolframModel"][{{x, y}, {z, y}} > {{x, z}, {y, z}, {w, z}}, {{0, 0}, {0, 0}}, 12, "LayeredCausalGraph"] 
There’s a very important feature of this graph: it contains no cycles. In other words, there’s a definite “flow of causality”. There’s a partial ordering of what events can affect what other events, and there’s never any looping back, and having an event affect itself.
There are different ways we can define “simultaneity surfaces”, corresponding to different foliations of this graph:
✕
Show[#, ImageSize > 400] & /@ {CloudGet["https://wolfr.am/KXgcRNRJ"]; evolution = ResourceFunction[ "WolframModel"][{{x, y}, {z, y}} > {{x, z}, {y, z}, {w, z}}, {{0, 0}, {0, 0}}, 12]; gg = Graph[evolution["LayeredCausalGraph"]]; GraphPlot[gg, Epilog > {Directive[Red], straightFoliationLines[{1/2, 0}, {0, 0}, (# &), {0, 1}]}], CloudGet["https://wolfr.am/KXgcRNRJ"];(*drawFoliation*) gg = Graph[ ResourceFunction[ "WolframModel"][{{x, y}, {z, y}} > {{x, z}, {y, z}, {w, z}}, {{0, 0}, {0, 0}}, 12, "LayeredCausalGraph"]]; semiRandomWMFoliation = {{1}, {1, 2, 4, 6, 9, 3}, {1, 2, 4, 6, 9, 3, 13, 19, 12, 26, 36, 5, 7, 10, 51, 14, 69, 18, 8, 25, 11, 34, 20, 35, 50, 17}, {1, 2, 4, 6, 9, 3, 13, 19, 12, 26, 36, 5, 7, 10, 51, 14, 69, 18, 8, 25, 11, 34, 20, 35, 50, 17, 24, 68, 47, 15, 92, 27, 48, 37, 21, 28, 42, 22, 30, 16, 32, 23, 33, 46, 64, 90, 94, 65, 88, 49, 67, 91, 66, 89}}; Quiet[drawFoliation[gg, semiRandomWMFoliation, Directive[Red]], FindRoot::cvmit]} 
But there’s always a way to do it so that all events in a given slice are “causally before” events in subsequent slices. And indeed whenever the underlying rule has the property of causal invariance, it’s inevitable that things have to work this way.
But if we break causal invariance, other things can happen. Here’s an example of the multiway system for a (string) rule that doesn’t have causal invariance, and in which the same state can repeatedly be visited:
✕
Graph[ResourceFunction["MultiwaySystem"][{"AB" > "BAB", "BA" > "A"}, "ABA", 5, "StatesGraph"], GraphLayout > {"LayeredDigraphEmbedding", "RootVertex" > "ABA"}] 
If we look at the corresponding (multiway) causal graph, it contains a loop:
✕
LayeredGraphPlot[ ResourceFunction["MultiwaySystem"][{"AB" > "BAB", "BA" > "A"}, "ABA", 4, "CausalGraphStructure"]] 
In the language of general relativity, this loop represents a closed timelike curve, where the future can affect the past. And if we try to construct a foliation in which “time systematically moves forward” we won’t be able to do it.
But the presence of these kinds of loops is a different phenomenon from the existence of space tunnels. In a space tunnel there’s connectivity in the spatial hypergraph that makes the (graph) distance between two points be shorter than you’d expect from the overall structure of the hypergraph. But it’s just connecting different places in space. An event that happens at one end of the space tunnel can affect events associated with distant places in space, but (assuming causal invariance, etc.) those events have to be “subsequent events” with respect to the partial ordering defined by the causal graph.
Needless to say, there’s all sorts of subtlety about the events involved in maintaining the space tunnel, the definition of distance being “shorter than you’d expect”, etc. But the main point here is that “jumping” between distant places in space doesn’t in any way require or imply “traveling backwards in time”. Yes, if you think about flat, continuum space and you imagine a tachyon going faster than light, then the standard equations of special relativity imply that it must be going backwards in time. But as soon as space itself can have features like space tunnels, nothing like this needs to be going on. Time—and the computational process that corresponds to it—can still progress even as effects propagate, say through space tunnels, faster than light to places that seem distant in space.
Causal Cones and Light Cones
OK, now we’re ready to get to the meat of the question of fasterthanlight effects in our models. Let’s say some event occurs. This event can affect a cone of subsequent events in the causal graph. When the causal graph is a simple grid, it’s all quite straightforward:
✕
CloudGet["https://wolfr.am/LcADnk1u"]; upTriangleGraph = diamondCausalGraphPlot[11, {0, 0}, {}, # &, "Up", ImageSize > 450]; HighlightGraph[upTriangleGraph, Style[Subgraph[upTriangleGraph, VertexOutComponent[upTriangleGraph, 8]], Red, Thick]] 
But in a more realistic causal graph the story is more complicated:
✕
With[{g = ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 8]["LayeredCausalGraph", AspectRatio > 1/2]}, HighlightGraph[g, Style[Subgraph[g, VertexOutComponent[g, 10]], Red, Thick]]] 
The “causal cone” of affected events is very well defined. But now the question is: how does this relate to what happens in space and time?
When one thinks about the propagation of effects in space and time one typically thinks of light cones. Given a source of light somewhere in space and time, where in space and time can this affect?
And one might assume that the causal cone is exactly the light cone. But things are more subtle than that. The light cone is normally defined by the positions in space and time that it reaches. And that makes perfect sense if we’re dealing with a manifold representing continuous spacetime, on which we can, for example, set up numerical coordinates. But in our models there’s not intrinsically anything like that. Yes, we can say what element in a hypergraph is affected after some sequence of events. But there’s no a priori way to say where that element is in space. That’s only defined in some limit, relative to everything else in the whole hypergraph.
And this is the nub of the issue of fasterthanlight effects in our models: causal (and, in a sense, temporal) relationships are immediately well defined. But spatial ones are not. One event can affect another through a single connection in the causal graph, but those events might be occurring at different ends of a space tunnel that traverses what we consider to be a large distance in space.
There are several related issues to consider, but they center around the question of what space really is in our models. We started off by talking about space corresponding to a collection of elements and relations, represented by a hypergraph. But the hypergraph is continually being updated. So the first question is: can we define an instantaneous snapshot of space?
Well, that’s what our reference frames, and foliations, and simultaneity surfaces, and so on, are about. They specify which particular collection of events we should consider to have happened at the moment when we “sample the structure of space”. There is arbitrariness to this choice, which corresponds directly to the arbitrariness that we’re used to in the selection of reference frames in relativity.
But can we choose any collection of events consistent with the partial ordering defined by the causal graph (i.e. where no events associated with a “single time slice” follow each other in the causal graph, and thus affect each other)? This is where things begin to get complicated. Let’s imagine we pick a foliation like this, or something even wilder:
✕
CloudGet["https://wolfr.am/LcADnk1u"]; upTriangleGraph = diamondCausalGraphPlot[9, {0, 0}, {}, # &, "Up", ImageSize > 450]; Show[ drawFoliation[ Graph[upTriangleGraph, VertexLabelStyle > Directive[8, Bold], VertexSize > .45], {{1}, {1, 3, 6, 10, 2, 4, 5}, {1, 3, 6, 10, 2, 4, 5, 8, 9, 15, 13, 14, 19, 20, 26, 7, 12}, {1, 3, 6, 10, 2, 4, 5, 8, 9, 15, 13, 14, 19, 20, 26, 7, 12, 11, 17, 21, 18, 25, 24, 27, 32, 34, 28, 33, 16, 23, 31, 35, 42}}, Directive[AbsoluteThickness[2], Red]], ImageSize > 550] 
We may know what the spatial hypergraph “typically” looks like. But perhaps with a weird enough foliation, it could be very different.
But for now, let’s ignore this (though it will be important later). And let’s just imagine we pick some “reasonable” foliation. Then we want to ask what the “projection” of the causal cone onto the instantaneous structure of space is. Or, in other words, what elements in space are affected by a particular event?
Let’s look at a specific example. Let’s consider the same rule and same causal cone as above, with the “flat” (“cosmological rest frame”) foliation:
✕
CloudGet["https://wolfr.am/KXgcRNRJ"]; With[{g = ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 8]["LayeredCausalGraph", AspectRatio > 1/2, Epilog > {Directive[Red], straightFoliationLines[{0.22, 0}, {0, 0}, (# &), {0, 2}]}]}, HighlightGraph[g, Style[Subgraph[g, VertexOutComponent[g, 10]], Red, Thick]]] 
Here are spatial hypergraphs associated with successive slices in this foliation, with the parts contained in the causal cone highlighted:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{"EffectiveSpatialBall", "[", RowBox[{"wmo_", ",", "expr0_"}], "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"t", "=", RowBox[{ "wmo", "[", ""<CompleteGenerationsCount>"", "]"}]}], ",", "fexprs"}], "}"}], ",", RowBox[{ RowBox[{"fexprs", "=", RowBox[{"wmo", "[", RowBox[{""<StateEdgeIndicesAfterEvent>"", ",", RowBox[{"", "1"}]}], "]"}]}], ";", RowBox[{"Intersection", "[", RowBox[{ RowBox[{"Cases", "[", RowBox[{ RowBox[{"VertexOutComponent", "[", RowBox[{ RowBox[{ "wmo", "[", ""<ExpressionsEventsGraph>"", "]"}], ",", RowBox[{"{", "expr0", "}"}]}], "]"}], ",", RowBox[{ RowBox[{"{", RowBox[{""<Expression>"", ",", "n_"}], "}"}], ":>", "n"}]}], "]"}], ",", "fexprs"}], "]"}]}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"EffectiveSpatialAtomBall", "[", RowBox[{"wmo_", ",", "expr0_"}], "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"t", "=", RowBox[{ "wmo", "[", ""<CompleteGenerationsCount>"", "]"}]}], ",", "fexprs"}], "}"}], ",", RowBox[{ RowBox[{"fexprs", "=", RowBox[{"wmo", "[", RowBox[{""<StateEdgeIndicesAfterEvent>"", ",", RowBox[{"", "1"}]}], "]"}]}], ";", RowBox[{ RowBox[{"wmo", "[", ""<AllExpressions>"", "]"}], "[", RowBox[{"[", RowBox[{"Intersection", "[", RowBox[{ RowBox[{"Cases", "[", RowBox[{ RowBox[{"VertexOutComponent", "[", RowBox[{ RowBox[{ "wmo", "[", ""<ExpressionsEventsGraph>"", "]"}], ",", RowBox[{"{", "expr0", "}"}]}], "]"}], ",", RowBox[{ RowBox[{"{", RowBox[{""<Expression>"", ",", "n_"}], "}"}], ":>", "n"}]}], "]"}], ",", "fexprs"}], "]"}], "]"}], "]"}]}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"EffectiveSpatialBallPlot", "[", RowBox[{"wmo_", ",", "expr0_"}], "]"}], ":=", RowBox[{"With", "[", RowBox[{ RowBox[{"{", RowBox[{"bb", "=", RowBox[{"EffectiveSpatialAtomBall", "[", RowBox[{"wmo", ",", "expr0"}], "]"}]}], "}"}], ",", RowBox[{"wmo", "[", RowBox[{""<FinalStatePlot>"", ",", RowBox[{"GraphHighlight", "[Rule]", RowBox[{"Join", "[", RowBox[{"bb", ",", RowBox[{"Union", "[", RowBox[{"Catenate", "[", "bb", "]"}], "]"}]}], "]"}]}]}], "]"}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{"Table", "[", RowBox[{ RowBox[{"If", "[", RowBox[{ RowBox[{"t", "<", "4"}], ",", RowBox[{ RowBox[{"ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "t", ",", ""<FinalStatePlot>""}], "]"}], ",", RowBox[{"EffectiveSpatialBallPlot", "[", RowBox[{ RowBox[{ RowBox[{ "ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "t"}], "]"}], ",", RowBox[{"{", RowBox[{""<Event>"", ",", "10"}], "}"}]}], "]"}]}], "]"}], ",", RowBox[{"{", RowBox[{"t", ",", "9"}], "}"}]}], "]"}]], "Input"] }, Open ]] 
For the first 3 slices the event that begins the causal cone hasn’t happened yet. But after that we start seeing the effect of the event, gradually spreading across successive spatial hypergraphs.
Yes, there are more subtleties ahead. But basically what we’re seeing here is the expansion of the light cone with time. So now we’ve got to ask the critical question: how fast does the edge of this light cone actually expand? How much space does it traverse at each unit in time? In other words, what is the effective speed of light here?
It is already clear from the pictures above that this is a somewhat subtle question. But let’s begin with an even more basic issue. The speed of light is something we measure in units like meters per second. But what we can potentially get from our model is instead a speed in spatial hypergraph edges per causal edge. We can say that each causal edge corresponds to a certain elementary time elapsing. And as soon as we quote the elementary time in seconds—say 100^{–100}s—we’re basically defining the second. And similarly, we can say that each spatial hypergraph edge corresponds to a distance of a certain elementary length. But now imagine that in t elementary times the light cone in the hypergraph has advanced by α t spatial hypergraph edges, or α t elementary lengths. What is α t in meters? It has to be α c t, where c is the speed of light, because in effect this defines the speed of light.
In other words, it’s at some level a tautology to say that the light cone in the spatial hypergraph advances at the speed of light—because this is the definition of the speed of light. But it’s more complicated than that. In continuum space there’s nothing inconsistent about saying that the speed of light is the same in every direction, everywhere. But when we’re projecting our causal cone onto the spatial hypergraph we can’t really say that anymore. But to know what happens we have to figure out more about how to characterize space.
In our models it’s clear what causal effects there are, and even how they spread. But what’s far from clear is where in detail these effects show up in what we call space. We know what the causal cones are like; but we still have to figure out how they map into positions in space. And from that we can try to work out whether—relative to the way we set up space—there can be effects that go faster than light.
How to Measure Distance
In a sense speeds are complicated to characterize in our models because positions and times are hard to define. But it’s useful to consider for a moment the much simpler case of cellular automata, where from the outset we just set up a grid in space and time. Given some cellular automaton, say with a random initial condition, we can ask how fast an effect can propagate. For example, if we change one cell in the initial condition, by how many cells per step can the effect of this expand? Here are a couple of typical results:
✕
With[{u = RandomInteger[1, 160]}, SeedRandom[24245]; ArrayPlot[ Sum[(2 + (1)^i) CellularAutomaton[#, ReplacePart[u, 80 > i], 80], {i, 0, 1}], ColorRules > {0 > White, 4 > Black, 1 > Red, 3 > Red}, ImageSize > 330]] & /@ {22, 30} 
The actual speed of expansion can vary, but in both cases the absolute maximum speed is 1 cell/step. And this is very straightforward to understand from the underlying rules for the cellular automata:
✕
RulePlot[CellularAutomaton[#], ImageSize > 300] & /@ {22, 30} 
In both cases, the rule for each step “reaches” one cell away, so 1 cell/step is the maximum rate at which effects can propagate.
There’s something somewhat analogous that happens in our models. Consider a rule like:
✕
RulePlot[ResourceFunction[ "WolframModel"][{{{1, 2}, {2, 3}} > {{2, 4}, {2, 4}, {4, 1}, {4, 3}}}]] 
A bit like in the cellular automaton, the rule only “reaches” a limited number of connections away. And what this means is that in each updating event only elements within a certain range of connections can “have an effect” on each other. But inevitably this is only a very local statement. Because while the structure of the rule implies that effects can only spread a certain distance in a single update there is nothing that says what the “relative geometry” of successive updates will be, and what connection might be connected to what. Unlike in a cellular automaton where the global spatial structure is predefined, in our models there is no immediate global consequence to the fact that the rules are fundamentally local with respect to the hypergraph.
It should be mentioned that the rules don’t strictly even have to be local. If the lefthand side is disconnected, as in
✕
RulePlot[ResourceFunction["WolframModel"][{{x}, {y}} > {{x, y}}]] 
then in a sense any individual update can pick up elements from anywhere in the spatial hypergraph—even disconnected parts. And as a result, something anywhere in the universe can immediately affect something anywhere else. But with a rule like this, there doesn’t seem to be a way to build up anything with the kind of locality properties that characterize what we think of as space.
OK, but given a spatial hypergraph, how do we figure out “how far” it is from one node to another? That’s a subtle question. It’s easy to figure out the graph distance: just find the geodesic path from one node to another and see how many connections it involves. But this is just an abstract distance on the hypergraph: now the question is how it relates to a distance we might measure “physically”, say with something like a ruler.
It’s a tricky thing: we have a hypergraph that is supposed to represent everything in the universe. And now we want something—presumably itself part of the hypergraph—to measure a distance in the hypergraph. In traditional treatments of relativity it’s common to think of measuring distances by looking at arrival times of light signals or photons. But this implicitly assumes that there’s an underlying structure of space, and photons are simply being added in to probe it. In our models, however, the photons have to themselves be part of the spatial hypergraph: they’re in a sense just “pieces of space”, albeit presumably with appropriate generalized topological properties.
Or, put another way: when we directly study the spatial hypergraph, we’re operating far below the level of things like photons. But if we’re going to compare what we see in spatial hypergraphs with actual distance measurements in physics we’re going to have to find some way to bridge the gap. Or, in other words, we need to find some adequate proxy for physical distance that we can compute directly on the spatial hypergraph.
A simple possibility that we’ve used a lot in practice in exploring our models is just graph distance, though with one wrinkle. The wrinkle is as follows: our hypergraphs represent collections of relations between elements, and we assume that these relations are ordered—so that the hyperedges in our hypergraphs are directed hyperedges. But in computing “physicallike distances” we ignore the directedness, and treat what we have as an undirected hypergraph. In the limit of sufficiently large hypergraphs, this shouldn’t make much difference, although it seems as if including directedness information may let us look at the analog of spinors, while the undirected case corresponds to ordinary vectors, which are what we’re more familiar with in terms of measuring distances.
So is there any other proxy for distance that we could use? Actually, there are several. But one that may be particularly good is directly derived from the causal graph. It’s in some ways the analog of what we might do in traditional discussions of relativity where we imagine a grid of beacons signaling to each other over a limited period of time. In terms of our models we can say that it’s the analog of a branchial distance for the causal graph.
Here’s how it works. Construct a causal graph, say:
✕
ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 5]["LayeredCausalGraph", AspectRatio > 1/2, VertexLabels > Automatic] 
Now look at the events in the last slice shown here. For each pair of events look at their ancestry, i.e. at what previous event(s) led to them. If a particular pair of events have a common ancestor on the step before, connect them. The result in this case is the graph:
✕
PacletInstall["SetReplace"]; << SetReplace`; SpatialReconstruction[wmo_WolframModelEvolutionObject, dt_Integer : 1] := Module[{cg = wmo["CausalGraph"], ceg = wmo["EventGenerations"], ev0, ev1, oc}, ev0 = First /@ Position[(ceg  Max[ceg]), dt]; ev1 = First /@ Position[(ceg  Max[ceg]), 0]; oc = Select[Rest[VertexOutComponent[cg, #]], MemberQ[ev1, #] &] & /@ ev0; Graph[ WolframPhysicsProjectStyleData["SpatialGraph", "Function"][ Graph[ev1, Flatten[(UndirectedEdge @@@ Subsets[#, {2}]) & /@ oc]]], VertexStyle > WolframPhysicsProjectStyleData["CausalGraph", "VertexStyle"], EdgeStyle > Blend[{First[ WolframPhysicsProjectStyleData["SpatialGraph", "EdgeLineStyle"]], WolframPhysicsProjectStyleData["BranchialGraph", "EdgeStyle"]}]]] Graph[SpatialReconstruction[ WolframModel[{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 5], 1], VertexLabels > Automatic] 
One can think of this as a “reconstruction of space”, based on the causal graph. In an appropriate limit, it should be essentially the same as the structure of space associated with the original hypergraph—though with this small a graph the spatial hypergraph still looks quite different:
✕
ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 5]["FinalStatePlot"] 
It’s slightly complicated, but it’s important to understand the differences between these various graphs. In the underlying spatial hypergraph, the nodes are the fundamental elements in our model—that we’ve dubbed above “atoms of space”. The hyperedges connecting these nodes correspond to the relations between the elements. In the causal graph, however, the nodes represent updating events, joined by edges that represent the causal relationships between these events.
The “spatial reconstruction graph” has events as its nodes, but it has a new kind of edge connecting these nodes—an edge that represents immediate common ancestry of the events. Whenever an event “causes” other events one can think of the first event as “starting an elementary light cone” that contains the other events. The causal graph represents the way that the elementary light cones are “knitted together” by the evolution of the system, and, more specifically, by the overlap of effects of different events on relations in the spatial hypergraph. The spatial reconstruction graph now uses the fact that two events lie in the same elementary light cone as a way to infer that the events are “close together”, as recorded by an edge in the spatial reconstruction graph.
There is an analogy here to our discussions of quantum mechanics. In talking about quantum mechanics we start from multiway graphs whose nodes are quantum states, and then we look at (“time”) slices through these graphs, and construct branchial graphs from them—with two states being joined in this branchial graph when they have an immediate common ancestor in the multiway graph. Or, said another way: in the branchial graph we join states that are in the same elementary “entanglement cone”. And the resulting branchial graph can be viewed as a map of a space of quantum states and their entanglements:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{ RowBox[{"ResourceFunction", "[", ""<MultiwaySystem>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{""<A>"", "[Rule]", ""<AB>""}], ",", RowBox[{""<B>"", "[Rule]", ""<A>""}]}], "}"}], ",", ""<A>"", ",", "4", ",", ""<EvolutionGraph>""}], "]"}], "//", "LayeredGraphPlot"}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"ResourceFunction", "[", ""<MultiwaySystem>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{""<A>"", "[Rule]", ""<AB>""}], ",", RowBox[{""<B>"", "[Rule]", ""<A>""}]}], "}"}], ",", ""<A>"", ",", "4", ",", ""<BranchialGraph>""}], "]"}]], "Input"] }, Open ]] 
The spatial reconstruction graph is the same idea: it’s like a branchial graph, but computed from the causal graph, rather than from a multiway graph. (Aficionados of our project may notice that the spatial reconstruction graph is a new kind of graph that we haven’t drawn before—and in which we’re coloring the edges with a new, purple color that happens to be a blend of our “branchial pink” with the bluegray used for spatial hypergraphs.)
In the spatial reconstruction graph shown above, we’re joining events when they have a common ancestor one step before. But we can generalize the notion of a spatial reconstruction graph (or, for that matter, a branchial graph) by allowing common ancestors more than one step back.
In the case we showed above, going even two steps back causes almost all events to have common ancestors:
✕
PacletInstall["SetReplace"]; << SetReplace`; SpatialReconstruction[wmo_WolframModelEvolutionObject, dt_Integer : 1] := Module[{cg = wmo["CausalGraph"], ceg = wmo["EventGenerations"], ev0, ev1, oc}, ev0 = First /@ Position[(ceg  Max[ceg]), dt]; ev1 = First /@ Position[(ceg  Max[ceg]), 0]; oc = Select[Rest[VertexOutComponent[cg, #]], MemberQ[ev1, #] &] & /@ ev0; Graph[ WolframPhysicsProjectStyleData["SpatialGraph", "Function"][ Graph[ev1, Flatten[(UndirectedEdge @@@ Subsets[#, {2}]) & /@ oc]]], VertexStyle > WolframPhysicsProjectStyleData["CausalGraph", "VertexStyle"], EdgeStyle > Blend[{First[ WolframPhysicsProjectStyleData["SpatialGraph", "EdgeLineStyle"]], WolframPhysicsProjectStyleData["BranchialGraph", "EdgeStyle"]}]]] Graph[SpatialReconstruction[ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 5], 2], VertexLabels > Automatic] 
And indeed if we go enough steps back, every event will inevitably share a common ancestor: the “big bang” event that started the evolution of the system.
Let’s say we have a rule that leads to a sequence of spatial hypergraphs:
✕
ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 10]["StatesPlotsList", ImageSize > Tiny] 
We can compare these with the spatial reconstruction graphs that we get from the causal graph for this system. Here are the results on successive steps, allowing a “lookback” of 2 steps:
✕
PacletInstall["SetReplace"]; << SetReplace`; SpatialReconstruction[wmo_WolframModelEvolutionObject, dt_Integer : 1] := Module[{cg = wmo["CausalGraph"], ceg = wmo["EventGenerations"], ev0, ev1, oc}, ev0 = First /@ Position[(ceg  Max[ceg]), dt]; ev1 = First /@ Position[(ceg  Max[ceg]), 0]; oc = Select[Rest[VertexOutComponent[cg, #]], MemberQ[ev1, #] &] & /@ ev0; Graph[ WolframPhysicsProjectStyleData["SpatialGraph", "Function"][ Graph[ev1, Flatten[(UndirectedEdge @@@ Subsets[#, {2}]) & /@ oc]]], VertexStyle > WolframPhysicsProjectStyleData["CausalGraph", "VertexStyle"], EdgeStyle > Blend[{First[ WolframPhysicsProjectStyleData["SpatialGraph", "EdgeLineStyle"]], WolframPhysicsProjectStyleData["BranchialGraph", "EdgeStyle"]}]]] Table[Graph[ SpatialReconstruction[ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, t], 2], ImageSize > Tiny], {t, 10}] 
And as the number of steps increases, there is increasingly commonality between the spatial hypergraph and the spatial reconstruction graph—though they are not identical.
It’s worth pointing out that the spatial reconstruction graphs we’ve drawn certainly aren’t the only ways to get a proxy for physical distances. One simple change is that we can look at common successors, rather than common ancestors.
Another thing is to look not at a spatial hypergraph in which the nodes are elements and the hyperedges are relations, but instead at a “dual spatial hypergraph” in which the nodes are relations and the hyperedges are associated with elements, with each (unordered) hyperedge recording which relations share a given element.
For example, for the spatial hypergraph
✕
ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 5, "FinalStatePlot"] 
the corresponding dual spatial hypergraph is
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{"RelationsElementsHypergraph", "[", "wmo_", "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"ix", "=", RowBox[{"wmo", "[", RowBox[{""<StateEdgeIndicesAfterEvent>"", ",", RowBox[{"", "1"}]}], "]"}]}], ",", "es"}], "}"}], ",", RowBox[{"Values", "[", RowBox[{"Merge", "[", RowBox[{ RowBox[{"Association", "@@@", RowBox[{"(", RowBox[{"Thread", "/@", RowBox[{"Thread", "[", RowBox[{ RowBox[{ RowBox[{"wmo", "[", ""<AllExpressions>"", "]"}], "[", RowBox[{"[", "ix", "]"}], "]"}], "[Rule]", "ix"}], "]"}]}], ")"}]}], ",", "Identity"}], "]"}], "]"}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"UnorderedHypergraphPlot", "[", RowBox[{"h_", ",", "opts___"}], "]"}], ":=", RowBox[{ RowBox[{"ResourceFunction", "[", ""<WolframModelPlot>"", "]"}], "[", RowBox[{"h", ",", "opts", ",", RowBox[{""<ArrowheadLength>"", "[Rule]", "0"}], ",", RowBox[{"EdgeStyle", "[Rule]", RowBox[{"<", RowBox[{ RowBox[{"{", RowBox[{"_", ",", "_", ",", RowBox[{"_", ".."}]}], "}"}], "[Rule]", "Transparent"}], ">"}]}], ",", RowBox[{""<EdgePolygonStyle>"", "[Rule]", RowBox[{"<", RowBox[{ RowBox[{"{", RowBox[{"_", ",", "_", ",", RowBox[{"_", ".."}]}], "}"}], "[Rule]", RowBox[{"Directive", "[", RowBox[{ RowBox[{"Hue", "[", RowBox[{"0.63", ",", "0.66", ",", "0.81"}], "]"}], ",", RowBox[{"Opacity", "[", "0.1", "]"}], ",", RowBox[{"EdgeForm", "[", RowBox[{"Directive", "[", RowBox[{ RowBox[{"Hue", "[", RowBox[{"0.63", ",", "0.7", ",", "0.5"}], "]"}], ",", RowBox[{"Opacity", "[", "0.7", "]"}]}], "]"}], "]"}]}], "]"}]}], ">"}]}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{"UnorderedHypergraphPlot", "[", RowBox[{"RelationsElementsHypergraph", "[", RowBox[{ RowBox[{"ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "5"}], "]"}], "]"}], "]"}]], "Input"] }, Open ]] 
and the sequence of dual spatial hypergraphs corresponding to the evolution above is:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{"RelationsElementsHypergraph", "[", "wmo_", "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"ix", "=", RowBox[{"wmo", "[", RowBox[{""<StateEdgeIndicesAfterEvent>"", ",", RowBox[{"", "1"}]}], "]"}]}], ",", "es"}], "}"}], ",", RowBox[{"Values", "[", RowBox[{"Merge", "[", RowBox[{ RowBox[{"Association", "@@@", RowBox[{"(", RowBox[{"Thread", "/@", RowBox[{"Thread", "[", RowBox[{ RowBox[{ RowBox[{"wmo", "[", ""<AllExpressions>"", "]"}], "[", RowBox[{"[", "ix", "]"}], "]"}], "[Rule]", "ix"}], "]"}]}], ")"}]}], ",", "Identity"}], "]"}], "]"}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"UnorderedHypergraphPlot", "[", RowBox[{"h_", ",", "opts___"}], "]"}], ":=", RowBox[{ RowBox[{"ResourceFunction", "[", ""<WolframModelPlot>"", "]"}], "[", RowBox[{"h", ",", "opts", ",", RowBox[{""<ArrowheadLength>"", "[Rule]", "0"}], ",", RowBox[{"EdgeStyle", "[Rule]", RowBox[{"<", RowBox[{ RowBox[{"{", RowBox[{"_", ",", "_", ",", RowBox[{"_", ".."}]}], "}"}], "[Rule]", "Transparent"}], ">"}]}], ",", RowBox[{""<EdgePolygonStyle>"", "[Rule]", RowBox[{"<", RowBox[{ RowBox[{"{", RowBox[{"_", ",", "_", ",", RowBox[{"_", ".."}]}], "}"}], "[Rule]", RowBox[{"Directive", "[", RowBox[{ RowBox[{"Hue", "[", RowBox[{"0.63", ",", "0.66", ",", "0.81"}], "]"}], ",", RowBox[{"Opacity", "[", "0.1", "]"}], ",", RowBox[{"EdgeForm", "[", RowBox[{"Directive", "[", RowBox[{ RowBox[{"Hue", "[", RowBox[{"0.63", ",", "0.7", ",", "0.5"}], "]"}], ",", RowBox[{"Opacity", "[", "0.7", "]"}]}], "]"}], "]"}]}], "]"}]}], ">"}]}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{"Table", "[", RowBox[{ RowBox[{"Show", "[", RowBox[{ RowBox[{"UnorderedHypergraphPlot", "[", RowBox[{"RelationsElementsHypergraph", "[", RowBox[{ RowBox[{ "ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "t"}], "]"}], "]"}], "]"}], ",", RowBox[{"ImageSize", "[Rule]", "Tiny"}]}], "]"}], ",", RowBox[{"{", RowBox[{"t", ",", "0", ",", "10"}], "}"}]}], "]"}]], "Input"] }, Open ]] 
There are still other possibilities, particularly if one goes “below” the causal graph, and starts looking not just at causal relations between whole events, but also at causal relations between specific relations in the underlying spatial hypergraph.
But the main takeaway is that there are various proxies we can use for physical distance. In the limit of a sufficiently large system, all of them should give compatible results. But when we’re dealing with small graphs, they won’t quite agree, and so we may not be sure what we should say the distance between two things is.
Causal Balls vs. Geodesic Balls
To measure speed, we basically have to divide distance by elapsed time. But, as I just discussed at some length, when we’re constructing space and time from something lower level, it’s not straightforward to say exactly what we mean by distance and by elapsed time, and how different possibilities will correspond to what we’d actually measure, say at a human scale.
But as a first approximation, let’s just ask about the effect of a single event. The effect of this event is captured by a causal cone:
✕
With[{g = ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 8]["LayeredCausalGraph", AspectRatio > 1/2]}, HighlightGraph[g, Style[Subgraph[g, VertexOutComponent[g, 10]], Red, Thick]]] 
We can say that the elapsed time associated with a particular slice through this causal cone is the graph distance from the event at the top of the cone to events in this slice. (How the slice is chosen is determined by the reference frame we’re using.)
So now we want to see how far the effect of the event spreads in space. The first step is to “project” the causal cone onto some representation of “instantaneous space”. We can do this with the ordinary spatial hypergraph:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{"EffectiveSpatialBall", "[", RowBox[{"wmo_", ",", "expr0_"}], "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"t", "=", RowBox[{ "wmo", "[", ""<CompleteGenerationsCount>"", "]"}]}], ",", "fexprs"}], "}"}], ",", RowBox[{ RowBox[{"fexprs", "=", RowBox[{"wmo", "[", RowBox[{""<StateEdgeIndicesAfterEvent>"", ",", RowBox[{"", "1"}]}], "]"}]}], ";", RowBox[{"Intersection", "[", RowBox[{ RowBox[{"Cases", "[", RowBox[{ RowBox[{"VertexOutComponent", "[", RowBox[{ RowBox[{ "wmo", "[", ""<ExpressionsEventsGraph>"", "]"}], ",", RowBox[{"{", "expr0", "}"}]}], "]"}], ",", RowBox[{ RowBox[{"{", RowBox[{""<Expression>"", ",", "n_"}], "}"}], ":>", "n"}]}], "]"}], ",", "fexprs"}], "]"}]}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"EffectiveSpatialAtomBall", "[", RowBox[{"wmo_", ",", "expr0_"}], "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"t", "=", RowBox[{ "wmo", "[", ""<CompleteGenerationsCount>"", "]"}]}], ",", "fexprs"}], "}"}], ",", RowBox[{ RowBox[{"fexprs", "=", RowBox[{"wmo", "[", RowBox[{""<StateEdgeIndicesAfterEvent>"", ",", RowBox[{"", "1"}]}], "]"}]}], ";", RowBox[{ RowBox[{"wmo", "[", ""<AllExpressions>"", "]"}], "[", RowBox[{"[", RowBox[{"Intersection", "[", RowBox[{ RowBox[{"Cases", "[", RowBox[{ RowBox[{"VertexOutComponent", "[", RowBox[{ RowBox[{ "wmo", "[", ""<ExpressionsEventsGraph>"", "]"}], ",", RowBox[{"{", "expr0", "}"}]}], "]"}], ",", RowBox[{ RowBox[{"{", RowBox[{""<Expression>"", ",", "n_"}], "}"}], ":>", "n"}]}], "]"}], ",", "fexprs"}], "]"}], "]"}], "]"}]}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"HighlightEffectiveSpatialBallPlot", "[", RowBox[{"wmo_", ",", "expr0_"}], "]"}], ":=", RowBox[{"With", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"bb", "=", RowBox[{"EffectiveSpatialAtomBall", "[", RowBox[{"wmo", ",", "expr0"}], "]"}]}], ",", RowBox[{"edges", "=", RowBox[{"wmo", "[", ""<FinalState>"", "]"}]}]}], "}"}], ",", RowBox[{"HighlightGraph", "[", RowBox[{ RowBox[{"Graph", "[", RowBox[{"DirectedEdge", "@@@", RowBox[{"Catenate", "[", RowBox[{ RowBox[{ RowBox[{"Partition", "[", RowBox[{"#", ",", "2", ",", "1"}], "]"}], "&"}], "/@", "edges"}], "]"}]}], "]"}], ",", RowBox[{"Style", "[", RowBox[{ RowBox[{"DirectedEdge", "@@@", RowBox[{"Join", "[", RowBox[{"bb", ",", RowBox[{"Union", "[", RowBox[{"Catenate", "[", "bb", "]"}], "]"}]}], "]"}]}], ",", "Red", ",", "Thick"}], "]"}]}], "]"}]}], "]"}]}]], "Input"], Cell[BoxData[ RowBox[{"HighlightEffectiveSpatialBallPlot", "[", RowBox[{ RowBox[{ RowBox[{"ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "9"}], "]"}], ",", RowBox[{"{", RowBox[{""<Event>"", ",", "10"}], "}"}]}], "]"}]], "Input"] }, Open ]] 
But to align with the most obvious notion of “elapsed time” in the causal cone it’s better to use the spatial reconstruction graph, whose nodes, just like those of the causal graph, are events:
✕
PacletInstall["SetReplace"]; << SetReplace`; SpatialReconstruction[wmo_WolframModelEvolutionObject, dt_Integer : 1] := Module[{cg = wmo["CausalGraph"], ceg = wmo["EventGenerations"], ev0, ev1, oc}, ev0 = First /@ Position[(ceg  Max[ceg]), dt]; ev1 = First /@ Position[(ceg  Max[ceg]), 0]; oc = Select[Rest[VertexOutComponent[cg, #]], MemberQ[ev1, #] &] & /@ ev0; Graph[ WolframPhysicsProjectStyleData["SpatialGraph", "Function"][ Graph[ev1, Flatten[(UndirectedEdge @@@ Subsets[#, {2}]) & /@ oc]]], VertexStyle > WolframPhysicsProjectStyleData["CausalGraph", "VertexStyle"], EdgeStyle > Blend[{First[ WolframPhysicsProjectStyleData["SpatialGraph", "EdgeLineStyle"]], WolframPhysicsProjectStyleData["BranchialGraph", "EdgeStyle"]}]]] With[{sg = SpatialReconstruction[ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 8], 2]}, HighlightGraph[sg, Style[Subgraph[sg, With[{g = ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 8][ "LayeredCausalGraph"]}, VertexOutComponent[g, 10]]], Red, Thick]]] 
Let’s “watch the intersection grow” from successive slices of the causal cone, projected onto spatial reconstruction graphs:
✕
PacletInstall["SetReplace"]; << SetReplace`; SpatialReconstruction[wmo_WolframModelEvolutionObject, dt_Integer : 1] := Module[{cg = wmo["CausalGraph"], ceg = wmo["EventGenerations"], ev0, ev1, oc}, ev0 = First /@ Position[(ceg  Max[ceg]), dt]; ev1 = First /@ Position[(ceg  Max[ceg]), 0]; oc = Select[Rest[VertexOutComponent[cg, #]], MemberQ[ev1, #] &] & /@ ev0; Graph[ WolframPhysicsProjectStyleData["SpatialGraph", "Function"][ Graph[ev1, Flatten[(UndirectedEdge @@@ Subsets[#, {2}]) & /@ oc]]], VertexStyle > WolframPhysicsProjectStyleData["CausalGraph", "VertexStyle"], EdgeStyle > Blend[{First[ WolframPhysicsProjectStyleData["SpatialGraph", "EdgeLineStyle"]], WolframPhysicsProjectStyleData["BranchialGraph", "EdgeStyle"]}]]] Table[With[{sg = SpatialReconstruction[ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, t], 2]}, HighlightGraph[sg, Style[Subgraph[sg, With[{g = ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 10][ "LayeredCausalGraph"]}, VertexOutComponent[g, 10]]], Red, Thick]]], {t, 3, 10}] 
Now the question we have to ask is: how “wide” is that area of intersection? The pictures make it clear that it’s not trivial to answer—or even precisely define—that question. Yes, in the continuum limit of sufficiently large graphs we’d better get something that looks like a light cone in continuum space, but it’s far from trivial how that limiting process might work.
We can think of the intersection of the causal cone with a spatial slice as defining a “causal ball” at a particular “time”. But now within that spatial slice we can ask about graph distances. So, for example, given a particular point in the slice we can ask what points lie within a certain graph distance of it—or, in other words, what the geodesic ball of some radius around that point is.
And fundamentally the computation of “speed” is all about the comparison of the “widths” of causal balls and of geodesic balls. Another way to look at this is to say that given two points in the causal ball (that by definition are produced from a common ancestor some “time” back) we want to know the “spatial distance” between them.
There are several ways we can assess “width”. We could compute the boundaries of causal balls, and for each point see what the “geodesically most distant” point is. Or we can just compute geodesic (i.e. spatial reconstruction graph) distances between all pairs of points in the causal ball. Here are distributions of these distances for each step shown above:
✕
PacletInstall["SetReplace"]; << SetReplace`; SpatialReconstruction[wmo_WolframModelEvolutionObject, dt_Integer : 1] := Module[{cg = wmo["CausalGraph"], ceg = wmo["EventGenerations"], ev0, ev1, oc}, ev0 = First /@ Position[(ceg  Max[ceg]), dt]; ev1 = First /@ Position[(ceg  Max[ceg]), 0]; oc = Select[Rest[VertexOutComponent[cg, #]], MemberQ[ev1, #] &] & /@ ev0; Graph[ WolframPhysicsProjectStyleData["SpatialGraph", "Function"][ Graph[ev1, Flatten[(UndirectedEdge @@@ Subsets[#, {2}]) & /@ oc]]], VertexStyle > WolframPhysicsProjectStyleData["CausalGraph", "VertexStyle"], EdgeStyle > Blend[{First[ WolframPhysicsProjectStyleData["SpatialGraph", "EdgeLineStyle"]], WolframPhysicsProjectStyleData["BranchialGraph", "EdgeStyle"]}]]] Table[Histogram[ Flatten[Module[{sg = SpatialReconstruction[ ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, t], 2], pts, dm}, pts = Intersection[ With[{g = ResourceFunction[ "WolframModel"][{{{x, y}, {x, z}} > {{x, z}, {x, w}, {y, w}, {z, w}}}, {{0, 0}, {0, 0}}, 10][ "LayeredCausalGraph"]}, VertexOutComponent[g, 10]], VertexList[sg]]; Outer[GraphDistance[sg, #1, #2] &, pts, pts]]], {1}, PlotRange > {{.5, 8.5}, Automatic}, Frame > True, FrameTicks > {Automatic, None}], {t, 5, 10}] 
How do we assess the “speed of light” from this? We might imagine we should look at the “outer edge” of this histogram, and see how it advances with “time”. If we do that, we get the result:
✕
Cell[CellGroupData[{Cell[BoxData[{ RowBox[{ RowBox[{"PacletInstall", "[", ""<SetReplace>"", "]"}], ";", RowBox[{"<<", "SetReplace`"}], ";"}], "n", RowBox[{ RowBox[{"SpatialReconstruction", "[", RowBox[{"wmo_WolframModelEvolutionObject", ",", RowBox[{"dt_Integer", ":", "1"}]}], "]"}], ":=", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"cg", "=", RowBox[{"wmo", "[", ""<CausalGraph>"", "]"}]}], ",", RowBox[{"ceg", "=", RowBox[{"wmo", "[", ""<EventGenerations>"", "]"}]}], ",", "ev0", ",", "ev1", ",", "oc"}], "}"}], ",", RowBox[{ RowBox[{"ev0", "=", RowBox[{"First", "/@", RowBox[{"Position", "[", RowBox[{ RowBox[{"", RowBox[{"(", RowBox[{"ceg", "", RowBox[{"Max", "[", "ceg", "]"}]}], ")"}]}], ",", "dt"}], "]"}]}]}], ";", "[IndentingNewLine]", RowBox[{"ev1", "=", RowBox[{"First", "/@", RowBox[{"Position", "[", RowBox[{ RowBox[{"", RowBox[{"(", RowBox[{"ceg", "", RowBox[{"Max", "[", "ceg", "]"}]}], ")"}]}], ",", "0"}], "]"}]}]}], ";", "[IndentingNewLine]", RowBox[{"oc", "=", RowBox[{ RowBox[{ RowBox[{"Select", "[", RowBox[{ RowBox[{"Rest", "[", RowBox[{"VertexOutComponent", "[", RowBox[{"cg", ",", "#"}], "]"}], "]"}], ",", RowBox[{ RowBox[{"MemberQ", "[", RowBox[{"ev1", ",", "#"}], "]"}], "&"}]}], "]"}], "&"}], "/@", "ev0"}]}], ";", RowBox[{"Graph", "[", RowBox[{ RowBox[{ RowBox[{"WolframPhysicsProjectStyleData", "[", RowBox[{""<SpatialGraph>"", ",", ""<Function>""}], "]"}], "[", RowBox[{"Graph", "[", RowBox[{"ev1", ",", RowBox[{"Flatten", "[", RowBox[{ RowBox[{ RowBox[{"(", RowBox[{"UndirectedEdge", "@@@", RowBox[{"Subsets", "[", RowBox[{"#", ",", RowBox[{"{", "2", "}"}]}], "]"}]}], ")"}], "&"}], "/@", "oc"}], "]"}]}], "]"}], "]"}], ",", RowBox[{"VertexStyle", "[Rule]", RowBox[{"WolframPhysicsProjectStyleData", "[", RowBox[{""<CausalGraph>"", ",", ""<VertexStyle>""}], "]"}]}], ",", RowBox[{"EdgeStyle", "[Rule]", RowBox[{"Blend", "[", RowBox[{"{", RowBox[{ RowBox[{"First", "[", RowBox[{"WolframPhysicsProjectStyleData", "[", RowBox[{ ""<SpatialGraph>"", ",", ""<EdgeLineStyle>""}], "]"}], "]"}], ",", RowBox[{"WolframPhysicsProjectStyleData", "[", RowBox[{ ""<BranchialGraph>"", ",", ""<EdgeStyle>""}], "]"}]}], "}"}], "]"}]}]}], "]"}]}]}], "]"}]}], "[IndentingNewLine]", RowBox[{"Table", "[", RowBox[{ RowBox[{"{", RowBox[{"t", ",", RowBox[{"Max", "[", RowBox[{"Flatten", "[", RowBox[{"Module", "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"sg", "=", RowBox[{"SpatialReconstruction", "[", RowBox[{ RowBox[{ RowBox[{ "ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "t"}], "]"}], ",", "2"}], "]"}]}], ",", "pts", ",", "dm"}], "}"}], ",", "n", RowBox[{ RowBox[{"pts", "=", RowBox[{"Intersection", "[", RowBox[{ RowBox[{"With", "[", RowBox[{ RowBox[{"{", RowBox[{"g", "=", RowBox[{ RowBox[{ RowBox[{ "ResourceFunction", "[", ""<WolframModel>"", "]"}], "[", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "y"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}]}], "}"}], "[Rule]", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"x", ",", "z"}], "}"}], ",", RowBox[{"{", RowBox[{"x", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"y", ",", "w"}], "}"}], ",", RowBox[{"{", RowBox[{"z", ",", "w"}], "}"}]}], "}"}]}], "}"}], ",", RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}], ",", RowBox[{"{", RowBox[{"0", ",", "0"}], "}"}]}], "}"}], ",", "12"}], "]"}], "[", ""<LayeredCausalGraph>"", "]"}]}], "}"}], ",", RowBox[{"VertexOutComponent", "[", RowBox[{"g", ",", "10"}], "]"}]}], "]"}], ",", RowBox[{"VertexList", "[", "sg", "]"}]}], "]"}]}], ";", RowBox[{"Outer", "[", RowBox[{ RowBox[{ RowBox[{"GraphDistance", "[", RowBox[{"sg", ",", "#1", ",", "#2"}], "]"}], "&"}], ",", "pts", ",", "pts"}], "]"}]}]}], "]"}], "]"}], "]"}]}], "}"}], ",", RowBox[{"{", RowBox[{"t", ",", "5", ",", "12"}], "}"}]}], "]"}]}], "Input"], Cell[BoxData[ RowBox[{"ListLinePlot", "[", RowBox[{"%", ",", RowBox[{"Mesh", "[Rule]", "All"}]}], "]"}]], "Input"] }, Open ]] 
But the full story is more complicated. Because, yes, the largescale limit should be like a light cone, where we can measure the speed of light from its slope. But that doesn’t tell us about the “fine structure”. It doesn’t tell us whether at the edge of the causal ball, there are, for example, effectively space tunnels that “reach out” in the geodesic ball.
There are lots of subtle issues here. And there’s another issue in the example we’ve been using: not only does this involve a causal cone that’s expanding, but the “whole universe” (i.e. the whole spatial hypergraph) is also expanding.
So why not look at a simpler, “more static” case? Well, it isn’t so easy. Because in our models space is being “made dynamically”: it can’t really ever be “static”. At best we might imagine just having a rule that “trivially tills space”, touching elements but not “doing much” to them. But doing this introduces its own collection of artifacts.
To Travel? To Communicate?
We’ve so far been talking mainly about the very lowlevel structure of spacetime, and how fast “threads of causality” can effectively “traverse space”. But if we’re actually going to be able to make use of fasterthanlight phenomena, we’ve somehow got to “send something through them”. It’s not good enough to just have the structure of spacetime show some kind of fasterthanlight phenomenon. We’ve got to be able to take something that we’ve chosen, and “send it through”.
When we talk about “traveling faster than light”, what we normally mean is that we can take ourselves, made of ordinary matter, atoms, etc. and transport that whole structure faster than light across space. A lower bar is to consider fasterthanlight communication. To do this we have to be able to take some message that we have chosen, and convert it to a form that can be transferred across space faster than light.
To achieve true fasterthanlight travel we presumably have to be able to construct some form of space tunnel in which the interior of the tunnel (and its entrance and exit) are sufficiently close to ordinary, flat space that they wouldn’t destroy us if we passed through them. It doesn’t seem difficult to imagine a spatial hypergraph that at least statically contains such a space tunnel. But it’s much more challenging to think about how this would be created dynamically.
But, OK, so let’s say we just want to send individual particles, like photons, through. Well, in our models it’s not clear that’s that much easier. Because it seems likely that even a single photon of ordinary energy will correspond to a quite large region in the spatial hypergraph. Presumably the “core” of the photon is some kind of persistent topologicallike structure in the hypergraph. And to understand the propagation of a photon, what one should do is to trace this structure in the causal graph.
What about “communication without travel”? To propagate a “signal” in space requires that the signal has persistence of some kind, and the most obvious mechanism for such persistence would be a topologicallike structure of the kind we assume exists in particles like photons. But—at least with some of the processes we’ll discuss below—there will be a premium on having our “signal carrier” involve as few underlying elements in the spatial hypergraph as possible. And one might imagine that this would be best achieved by something like the oligon particles that our models suggest could exist, and that involve many fewer elements in the spatial hypergraph than the particles we currently know about.
Of course, using “oligon radio” requires that we have some kind of transducer between ordinary familiar particles and oligons, and it’s not clear how that can be achieved.
There is probably a close connection in our models between what we might think of as black holes and what we might think of as particles. Quite what the details of this connection or correspondence are we don’t know yet, but both correspond to persistent structures “created purely from the structure of space”.
And it’s quite possible that there is a whole spectrum of persistent structures that don’t quite have characteristics like particles (indeed, our space tunnels would presumably be examples). The question of whether any of these can be used for communication is in a sense quite easy to define. To communicate, we need some structure in the causal graph that maintains information through time, and that has parts that can be arbitrarily changed. In other words, there needs to be some way to encode something like arbitrary patterns of bits in the causal graph, and have them persist.
The Second Law of Thermodynamics
I’ve been interested in the Second Law of thermodynamics and its origins for nearly 50 years, and it’s remarkable that it now seems to be intimately connected to questions about going faster than light in our models. Fundamentally, what the Second Law says is that initially orderly configurations of things like molecules have a seemingly inexorable tendency to become more disorderly over time. And as we’ll discuss, this is something very general, ultimately rooted in the general phenomenon of computational irreducibility. And it doesn’t just apply to familiar things like molecules: it also applies—in our models—to the very structure of space.
So what’s the underlying story of the Second Law? I thought about this for many years, and finally in the 1990s got to the point where I felt I understood it. At first, the Second Law seems like a paradox: if the laws of physics are reversible then one would think that one could run any process as well backwards as forwards. Yet what the Second Law—and our experience—says is that things that start orderly tend to become more disorderly.
But here’s a simple model that illustrates what’s going on. Consider a cellular automaton that’s reversible (like the standard laws of physics), in the sense that for every configuration (or, actually, in this case, every pair of configurations) there’s both a unique successor in time, and a unique predecessor. Now start the cellular automaton from a simple initial condition:
✕
ArrayPlot[ CellularAutomaton[{10710, {2, {{0, 8, 0}, {4, 2, 1}}}, 1, 2}, {{{1}, {1}}, 0}, 51]] 
We see a fundamental computational fact: just like my favorite rule 30 cellular automaton, even though the initial condition is simple, the system behaves in a complex—and in many ways seemingly random—way.
But here’s the thing: this happens both if one runs it forward in time, and backward:
✕
ArrayPlot[ CellularAutomaton[{10710, {2, {{0, 8, 0}, {4, 2, 1}}}, 1, 2}, Take[Reverse[ CellularAutomaton[{10710, {2, {{0, 8, 0}, {4, 2, 1}}}, 1, 2}, {{{1}, {1}}, 0}, 51]], 2], 101]] 
The randomization is just a feature of the execution of the rule—forward or backward. At some moment we have a configuration that looks simple. But when we run it forward in time, it “randomizes”. And the same happens if we go backward in time.
But why is there this apparent randomization? The evolution of the cellular automaton is effectively performing a computation. And to recognize a pattern in its output we have to do a computation too. But the point is that as soon as the evolution of the cellular automaton is computationally irreducible, recognizing a pattern inevitably takes an irreducible amount of computational work. It’s as if the cellular automaton is “encrypting” its initial condition—and so we have to do lots of computational work (perhaps even exponentially more than the cellular automaton itself) to be able to “decrypt” it.
It’s not that it’s impossible to invert the final state of the cellular automaton and find that it evolved from a simple state. It’s just that to do so takes an irreducible amount of computational work. And if we as observers are bounded in our computational capabilities we eventually won’t be able to do it—so we won’t be able to recognize that the system evolved from a simple state.
The picture above shows that once we have a simple state it’ll tend to evolve to a randomized state—just like we typically see. But the picture also shows that we can in principle set up a complicated initial state that will evolve to produce the simple state. So why don’t we typically see this happening in everyday life? It’s basically again a story of limited computational capabilities. Assume we have some computational system for setting up initial states. Then we can readily imagine that it would take only a limited number of computational operations to set up a simple state. But to set up the complicated and seemingly random state we’d need to be able to evolve to the simple state will take a lot more computational operations—and if we’re bounded in our computational capabilities we won’t be able to do it.
What we’ve seen here in a simple cellular automaton also happens with gas molecules—or idealized hard spheres. Say you start the molecules off in some special “simple” configuration, perhaps with all the molecules in the corner of a box. Then you let the system run, with molecules repeatedly colliding and so on. Looked at in a computational way, we can say that the process of evolution of the system is a computation—and we can expect that it will be a computationally irreducible one. And just like with the cellular automaton, any computationally bounded observer will inevitably see “SecondLaw behavior”.
The traditional treatment of the Second Law talks a lot about entropy—which measures the number of possible configurations consistent with a measurement one makes on the system. (Needless to say, counting configurations is a lot easier in a fundamentally discrete system like a cellular automaton, than in standard realnumber classical mechanics.) Well, if we measure the value of every single cell in a cellular automaton, there’s only one configuration consistent with our measurement—and given this measurement the whole past and future of the cellular automaton is determined, and we’ll always measure the same entropy for it.
But imagine instead that we can’t do such complete and precise measurements. Then there may be many configurations of the system consistent with the results we get. But the point is that if the actual configuration of the system is actually simple, computationally bounded measurements will readily be able to recognize this, and determine that there’s only one (or a few) configurations consistent with their results. But if the actual configuration is complicated, computationally bounded measurements won’t be able to determine which of many configurations one’s looking at. The result is that in terms of such measurements, the entropy of the system will be considered larger.
In the typical treatment of statistical mechanics over the past century one usually talks about “coarsegrained” measurements, but it’s always been a bit unclear what constitutes a “valid” coarse graining. I think what we now understand about computational irreducibility finally clarifies this, and lets us say what’s really going on in the Second Law: entropy seems to increase because the irreducible computation done by a system can’t successfully be “decrypted” by a computationally bounded observer.
Even back in the 1860s James Maxwell realized that if you could have a “demon” who basically tweaked individual molecules to unrandomize a gas, then you wouldn’t see SecondLaw behavior. And, yes, if the demon had sufficient computational capabilities you could make this work; the Second Law relies on the idea that no such computational capabilities are available.
And as soon as the Second Law is in effect, one can start “assuming that things are random”, or, more specifically, that at least in some aggregate sense, the behavior of a system will follow statistical averages. This assumption is critical in deriving standard continuum fluid behavior from underlying molecular dynamics. And it’s also critical in deriving the continuum form of space from our underlying discrete model—and for deriving things like special and general relativity.
In other words, the fact that a fluid—or space—seems like a continuum to us is a reflection of the boundedness of our computational capabilities. If we could apply as much computation as the underlying molecules in the gas—or the discrete elements in space—then we could recognize many details that would go beyond the continuum description. But with bounded computation, we just end up describing fluids—or space—in terms of aggregate continuum parameters.
We talk about mechanical work—that involves patterns of motion in molecules that we can readily recognize as organized—being useful. And we talk about “heat”—that involves patterns of motion in molecules that seem random to us—as being fundamentally less useful. But this is really just a reflection of our computational boundedness. There is all sorts of detailed information in the motions associated with heat; it’s just that we can’t decode them to make use of them.
Today when we describe a gas we’ll typically say that it’s characterized by temperature and pressure. But that misses all the detail associated with the motion of molecules. And I suspect that in time the coarseness of our current descriptions of things like gases will come to seem quite naive. There’ll be all sorts of other features and parameters that effectively correspond to different kinds of computations performed on the configuration of molecules.
People sometimes talk disparagingly about the possible “heat death of the universe”, in which all of the orderly “mechanical work” motion has degraded into “heat”. But I don’t think that’s the right characterization. Yes, our current ways of looking at microscopic motions might only be to say it’s “generic heat”. But actually there’ll be all this rich structure in there, if only we were making the right measurements, and doing the right computations.
Space Demons
If our models are going to reproduce what we currently know about physics, it’s got to be the case that in some largescale limit, casual balls behave essentially like geodesic balls expanding at the speed of light. But this will only be an aggregate statement—that doesn’t, for example, talk about each individual relation in the spatial graph.
Computational irreducibility implies that—just like with molecules in a gas—the configurations of the evolving spatial hypergraph will tend to appear seemingly random with respect to sufficiently bounded computations. And it’s important for us to use this in doing statistical averaging for our mathematical derivations.
But the question is: Can we “compute around” that seeming randomness? Perhaps at the edge of the causal cone there are lots of little space tunnels that transiently arise from the detailed underlying dynamics of the system. But will these just seem to arise “randomly”, or can we compute where they will be, so we can potentially make use of them?
In other words, can we have a kind of analog of Maxwell’s demon not for molecules in a gas, but for atoms of space: what we might call a “space demon”? And if we had such an entity, could it let us go faster than light?
Let’s look again at the case of gas molecules. Consider an idealized hardsphere gas in a box and track the motion of one of the “molecules”:
✕
CloudGet["https://wolfr.am/PYKieD46"]; GraphicsGrid[ Partition[Rest[visualize2D[20, 2000, 10, 2, 200]], 5]] 
The molecule bounces around having a sequence of collisions, and moves according to what seems to be a random walk. But now let’s imagine we have a “gas demon” who’s “riding on a molecule”. And every time its molecule collides with another one, let’s imagine that the demon can make a decision about whether to stay with the molecule it’s already on, or to jump to the other molecule in the collision.
And now let’s say the demon is trying to “compute its way” across the box, deciding by looking at the history of the system which molecule it should hitch a ride on at each collision. Yes, the demon will have to do lots of computation. But the result will be that it can get itself transported across the system much faster than if it just stuck with one molecule. In other words, by using computation, it can “beat randomness” (and diffusion).
If we think of the collisions between hard spheres as events, we can construct a causal graph of their causal relationships:
SeedRandom[1234]; hscg = Graph[ResourceFunction["WolframPhysicsProjectStyleData"][ "CausalGraph"]["Function"][genCausalGraph[20, 500, 10, 2]], AspectRatio > .9]
At each event there are two incoming causal edges and two outgoing ones, corresponding to the spheres involved in a particular collision. And we can think of what the demon is doing as having to choose at each node in the causal graph which outgoing edge to follow. Or, in other words, the demon is determining its path in the causal graph.
Just like for our models, we can construct a causal cone for the hardsphere gas (here continuing for more steps)—and the path taken by the demon is restricted to not go outside this cone:
HighlightGraph[hscg, Style[Subgraph[hscg, VertexOutComponent[hscg, {SortBy[VertexList[hscg], Last][[25]]}]], Red, Thick]]
But also like for our models, the relationship between positions in the causal ball obtained from this causal cone, and actual spatial positions, is in general complicated. At least if we were operating in an infinite region (as opposed to a finite box), the border of the causal ball in the hardsphere gas would just be a circle. But the point is that there are always “tendrils” that stick out, and if there’s a finite box, it’s even more complicated:
With[{boxSize = 20}, Graphics[ {{FaceForm[], EdgeForm[Black], Rectangle[{boxSize, boxSize}, {boxSize, boxSize}]}, MapIndexed[ Style[Disk[#, rad], EdgeForm[GrayLevel[.2]], If[MemberQ[mems, First[#2]], Lighter[Red, .2], Gray]] &, trajectories2D[200, 500, 20][[All, 500]]]}]]
But the point is that if the demon can make a judicious choice of which “tendrils” to follow, it can move faster than the speed defined by the “average border” of the causal cone.
If our “hardsphere gas” were made, for example, of idealized electronic turtles, each with a computer and sensors on board, it wouldn’t seem too difficult to have a “demon turtle”. Even if our “hard spheres” were the size of microorganisms, it wouldn’t seem surprising to have a “demon”. It’s harder to imagine for actual molecules or particles; there just doesn’t seem to be anywhere to “put the computation apparatus”. Though if we started thinking about cooperation among many different hard spheres then it begins to seem more plausible again. After all, perhaps we could set up a configuration of a group of hard spheres,whose evolution will do the computation we need.
OK, so what about the case of actual space in our models? In some ways it’s a more demanding situation: after all, every aspect of the internal structure of a space demon must—like everything else—be encoded in the structure of the spatial hypergraph.
There is much we don’t know yet. For example, if there are “transient space tunnels” formed, what regularities might they show? In a hardsphere gas, especially in 2D, there are surprisingly long time correlations between spheres, associated with what amounts to collective “hydrodynamic” behavior. And we don’t know what similar phenomena might exist in the spatial hypergraphs in our models.
But then, of course, there is the question of how to actually construct “space demons” to take advantage of transient space tunnels. The Principle of Computational Equivalence has both good and bad news here. The bad news is that it implies that the evolution of the spatial hypergraph will show computational irreducibility—so it’ll take irreducible amounts of computational work to predict what it does. But the good news is that the dynamics of the hypergraph will be capable of universal computation, and can therefore in principle be “programmed” to do computations that could do whatever can be done to “figure out what will happen”.
The key question is then whether there are sufficient “pockets of computational reducibility” associated with space tunnels that we’ll be able to successfully exploit. We know that in the continuum limit there’s plenty of computational reducibility: that’s why our models can reproduce mathematical theories like general relativity and quantum mechanics.
But space tunnels aren’t a phenomenon of the usual continuum limit; they’re something different. We don’t know what a “mathematical theory of space tunnels” would be like. Conceivably, insofar as ordinary continuum behavior can be thought of as related to the central limit theorem and Gaussian distributions, a “theory of space tunnels” could have something to do with extreme value distributions. But most likely the mathematics—if it exists, and if we can even call it that—will be much more alien.
When we say that a gas can be characterized as having a certain temperature, we’re saying that we’re not going to describe anything about the specific motions of the molecules; we’re just going to say that they’re “random”, with some average speed. But as I mentioned above, in reality there are all sorts of detailed patterns and correlations in these motions. And while as a whole they will show computational irreducibility, it is inevitable that there will be pockets of computational reducibility too. We don’t know what they are—and perhaps if we did, we could even use some of them for technological purposes. (Right now, we pretty much only use the very organized motions of molecules that we call “mechanical work”.)
But now the challenge in creating a space demon is to find such pockets of reducibility in the underlying behavior of space. In a sense, much of the historical task of engineering has been to identify pockets of reducibility in our familiar physical world: circular motion, ferromagnetic alignment of spins, wave configurations of fields, etc. In any given case, we’ll never know how hard it’s going to be: the process of finding pockets of reducibility is itself a computationally irreducible process.
But let’s say we could construct a space demon. We don’t know what characteristics it would have. Would it let us create borders around a space tunnel that would allow some “standard material object” to pass through the tunnel? Or would it instead allow a space tunnel to be constructed that could only pass through some special kind of hypergraph structure—that we might even characterize (in a nod to science fiction) as a means of “subspace communication” (i.e. communication that’s making use of structures that lie “below” space as we usually experience it)?
Quantum Effects
Most of what I’ve said about causal graphs, etc. so far has basically been classical. I’ve assumed that there’s in a sense just one thread of history for the universe. But the full story in our models—and in physics—is more complicated. Instead of there being a single theory of history, there’s a whole multiway graph that includes all the possible choices for how updating events can happen.
And in general instead of just having an ordinary causal cone, one really has a multiway causal cone—that in effect has extent not only in physical space but also in branchial space. And just as we have talked about selecting reference frames in spacetime, we also need to talk about selecting quantum observation frames in branchtime. And just as reference frames in spacetime give us a way to make sense of how events are organized in spacetime, and how we would observe or measure them there, so similarly quantum observation frames give us a way to make sense of how events are organized in branchtime, and what we would infer about them from quantum measurements.
In what we’ve said so far about space tunnels, we’re basically always assuming there’s a single thread of history involved. But really we should be talking about multiway causal cones, and tunnels that have extent both in physical space and branchial space, or, in other words, multispace tunnels.
We might imagine space tunnels are always “just fluctuations”, and that they’d be different on every “branch of history”. But a key point about multiway systems—and about multispace—is that they imply that we can expect coherence not only in physical space but also in branchial space, just as a “wave packet” is bounded both in physical and branchial space.
In our models, “vacuum fluctuations” in quantum mechanics and in the structure of space are intimately connected; in the end they are both just facets of the multiway causal graph. In ordinary quantum field theory one is used to virtual particles which individually have propagators (typically like ) that imply they can show “virtual” fasterthanlight effects. But we also know—as technically implemented in the commutation relations for field operators—that in the structure of standard quantum field theory there can be no real correlations “outside the light cone”. In our models, there can also be no correlations outside the (multiway) causal cone. But the whole issue is how projections of that multiway causal cone map onto geodesic balls representing distance in space.
So what does all this mean for space demons? That they actually need to be not just space demons, but multispace demons, operating not just in physical space, but also in branchial space, or in the space of quantum states. And, yes, this is yet more complicated, but it doesn’t in any obvious way change whether things are possible.
When we imagine a space demon identifying features of space that can form a space tunnel, we can expect that it’ll do this at a particular place in physical space. In other words, if we end up going faster than light, there’ll be a particular origination point in our physical space for our journey (or, in some science fiction terms, our “jump”). And it’s really no different for branchial space and multispace demons. A multispace tunnel will presumably have some location both in physical space and branchial space.
In the way we currently think about things, “going there” in branchial space basically means doing a certain quantum measurement—though causal invariance implies that in the end all quantum observers will agree about what happened (and e.g. that one successfully “went faster than light”).
It’s all quite complicated, and certainly far from completely worked out. And there’s another issue as well. The speed of light constrains maximum speeds in physical space. But in our models, there’s also the maximum entanglement speed, which constrains maximum speeds in branchial space. And just as we can imagine space tunnels providing ways to go “faster than c”, so also we can imagine multispace tunnels providing ways to go “faster than ζ”.
Is It Possible? Can We Make It Work?
OK, so what’s the bottom line? Is it in principle possible to go faster than light? And if so, how can we actually do it?
I’m pretty sure that, yes, in principle it’s possible. In fact, as soon as one views space as having an underlying structure, and not just being a mathematical manifold “all the way down”, it’s pretty much inevitable. But it still requires essentially “hacking” space, and “reverse engineering” its structure to find features like “space tunnels” that one can use.
How is all this consistent with relativity, and its assumption of the absoluteness of the speed of light? Well, it isn’t. The phenomena and possibilities I’m describing here are ones that occur in the “substrate” below where relativity operates. It’s as if our standard physics—with relativity, etc.—are part of the “highlevel operating system” of the universe. But what we’re talking here about doing is creating hacks down at the “machine code” level.
Put another way: relativity is something that arises in our models as a largescale limit, when one’s averaged out all the underlying details. But the whole point here is to somehow leverage and “line up” those underlying details, so they produce the effects we’re interested in. But when we look at the whole “bulk” universe, and the full largescale limit, anything we might be able to do at the level of the details will seem infinitesimal—and won’t affect our overall conclusion that relativity is a feature of the general physics of the universe.
Now of course, even though something may in principle be possible, that doesn’t mean it can be done in practice. Maybe it’s fairly easy to go a tiny distance faster than light, but to scale up to anything substantial requires resources beyond what we—or even the universe—could ever muster. And, yes, as I discussed, that is a possibility. Because in a sense what we have to do is to “beat computational irreducibility” in the evolution of space. And in the abstract there is no way to tell how hard this might be.
Let’s say we have the general objective of “going faster than light”. There will be an immense (and probably infinite) number of detailed ways we could imagine achieving this. And in general there will be no upper bound on the amount of computation needed for any one of them. So if we ask “Will any of them work?”, that’ll be formally undecidable. If we find one that we can show works, great. But we could in principle have to go on testing things forever, never being sure that nothing can work.
And, yes, this means that even though we might know the final underlying rule for physics, we still might fundamentally never be sure whether it’s possible to go faster than light. We might have successfully “reduced physics to mathematics”, but then we still have all the issues of mathematics—like Gödel’s theorem—to contend with. And just as Gödel’s theorem tells us there’s no upper bound on the lengths of proofs we might need in arithmetic, so now we’re in a situation where there’s no upper bound on the “complexity of the process” that we might need in physics to establish whether it’s possible to go faster than light.
Still, just because something is in general undecidable, it doesn’t mean we won’t be able to figure it out. Maybe we’ll have to give up on transporting ordinary material faster than light, and we’ll only be dealing with some specially crafted form of information. But there’s no reason to think that with an objective as broad as “somehow go faster than light” that we won’t be able to, in effect, find some pocket of computational reducibility that makes it possible for us to do it.
And the fact is that the history of engineering is full of cases where an initial glimmer of possibility was eventually turned into largescale technological success. “Can one achieve heavierthanair flight?” There were detailed hydrodynamic effects, and there were pieces of what later became control theory. And eventually there was an engineering construction that made it work.
It’s hard to predict the process of engineering innovation. We’ve known the basic physics around controlled nuclear fusion for more than half a century. But when will we actually make it work as an engineering reality? Right now the idea of hacking space to go faster than light seems far away from anything we could in practice do. But we have no idea how high—or low—the barrier actually is.
Might it require having our own little black hole? Or might it be something that just requires putting together things we already have in just the right way? Not long ago it was completely unclear that we could “beat the uncertainty principle” enough to measure gravitational waves. Or that we could build an atomic force microscope that could move individual atoms around. Or that we could form a physical Bose–Einstein condensate. But in cases like these it turned out that we already had the “raw materials” we needed; we just had to figure out what to do with them.
A few years ago, when I was trying to make up fictional science for the movie Arrival, I thought a little about how a presentday physicist might think about the mechanism for an interstellar spacecraft that showed up one day. It was before our current models, but I had already thought a lot about the potential discrete structure of spacetime. And the best fictional idea I came up with then about how to “access it” was through some kind of “gravitational laser”. Gravitons, like photons, are bosons that can in principle form quantum condensates. And at least at the level of a madeforamovie whiteboard I figured out a little of how this might work.
But from what we know now, there are other ideas. Perhaps the best analogy—at least for “communication” if not “travel”—is that one’s trying to get a signal “through a complex medium” as efficiently as possible. And that’s of course been the basic problem forever in communications systems based on electrical, electromagnetic or optical processes.
Often it’s been claimed that there’s some fundamental limit, say to transmission rates. But then an engineering solution will be found that overcomes it. And actually the typical mechanism used is a little like our demons. If one’s signal is going to be degraded by “noise”, figure out how to predict the noise, then “sculpt” the process of transmission around it. In 5G technology for example, there’s even an explicit concept of “pilot signals” that continually probe the local radio environment so that actual communication signals can be formed in just the right ways.
But, OK, let’s say there is a practical way to go faster than light, or at least to send signals faster than light. Then why aren’t we seeing lots of moreadvancedthanus extraterrestrial intelligences doing this all over the universe? Maybe we just have to figure out the right engineering trick and then we’ll immediately be able to tap into a universescale conversation. And while it’s fun to imagine just how wild the social network of the universe might get, I think there’s a fundamental problem here (even beyond the “what’s really the use case?”). Let’s say we can see processes that correspond to fasterthanlight communication. Are they part of a “conversation”, “saying” something meaningful? Or are they just “physical processes” that are going on?
Well, of course, anything that happens in the universe is, essentially by definition, a “physical process”. So then we might start talking about whether what we’re seeing is an “intentionally created” physical process, or one that’s just “happening naturally”. But—as I’ve written extensively about elsewhere—it’s a slippery slope. And the Principle of Computational Equivalence basically tells us that in the end we’ll never be able to distinguish the “intelligent” from the “merely computational”, or, given our model of physics, the “merely physical”—at least unless what we’re seeing is aligned in detail with our particular human ways of thinking.
At the outset we might have imagined that going faster than light was an openandshut case, and that physics had basically proved that—despite a few seemingly pathological examples in general relativity—it isn’t possible. I hope what’s become clear here is that actually the opposite is true. In our models of physics, going faster than light is almost inevitably possible in principle. But to actually do it requires engineering that may be irreducibly difficult.
But maybe it’s like in 1687 when a thennew model of physics implied that artificial satellites might be possible. After 270 years of steady engineering progress, there they were. And so it may be with going faster than light. Our models now suggest it’s possible. But whether the engineering required can be done in ten, a hundred, a thousand, a million or a billion years we don’t know. But maybe at least there’s now a path to turn yet another “puresciencefiction impossibility” into reality.
A Few Questions
My talk at NASA generated many questions. Here are a few answers.
What about warp bubbles and the Alcubierre metric?
Warp bubbles are a clever way to get something a bit like fasterthanlight travel in ordinary general relativity. The basic idea is to set up a solution to Einstein’s equations in which space is “rapidly contracting” in front of a “bubble region”, and expanding behind it:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{"expansion", "=", RowBox[{ RowBox[{"(", RowBox[{ InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], " ", RowBox[{ InterpretationBox[ StyleBox["Coth", ShowAutoStyles>False, AutoSpacing>False], Coth, Editable>False], "[", RowBox[{ InterpretationBox[ StyleBox["R", ShowAutoStyles>False, AutoSpacing>False], $CellContext`R, Editable>False], " ", InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False]}], "]"}], " ", RowBox[{"(", RowBox[{ RowBox[{"", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["Sech", ShowAutoStyles>False, AutoSpacing>False], Sech, Editable>False], "[", RowBox[{ InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], " ", RowBox[{"(", RowBox[{ RowBox[{"", InterpretationBox[ StyleBox["R", ShowAutoStyles>False, AutoSpacing>False], $CellContext`R, Editable>False]}], "+", SqrtBox[ RowBox[{ SuperscriptBox[ RowBox[{"(", RowBox[{ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], ")"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}]]}], ")"}]}], "]"}], "2"]}], "+", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["Sech", ShowAutoStyles>False, AutoSpacing>False], Sech, Editable>False], "[", RowBox[{ InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], " ", RowBox[{"(", RowBox[{ InterpretationBox[ StyleBox["R", ShowAutoStyles>False, AutoSpacing>False], $CellContext`R, Editable>False], "+", SqrtBox[ RowBox[{ SuperscriptBox[ RowBox[{"(", RowBox[{ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], ")"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}]]}], ")"}]}], "]"}], "2"]}], ")"}], " ", RowBox[{"(", RowBox[{ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], ")"}], " ", RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[Prime]", MultilineFunction>None], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], ")"}], "/", RowBox[{"(", SqrtBox[ RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "2"], "", RowBox[{"2", " ", InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], " ", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], "+", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}]], ")"}]}]}], ";"}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{ RowBox[{"expansionF", "[", RowBox[{"x_", ",", "[Rho]_"}], "]"}], "=", RowBox[{ RowBox[{ RowBox[{"expansion", "/.", RowBox[{"{", RowBox[{ RowBox[{"[Sigma]", "[Rule]", "8"}], ",", RowBox[{"R", "[Rule]", "1"}]}], "}"}]}], "/.", RowBox[{"{", RowBox[{"xs", "[Rule]", RowBox[{"Function", "[", RowBox[{"t", ",", "t"}], "]"}]}], "}"}]}], "/.", RowBox[{"{", RowBox[{ RowBox[{ RowBox[{"t", "[", "]"}], "[Rule]", "0"}], ",", RowBox[{ RowBox[{"x", "[", "]"}], "[Rule]", "x"}], ",", RowBox[{ RowBox[{ RowBox[{"y", "[", "]"}], "^", "2"}], "[Rule]", RowBox[{ RowBox[{"[Rho]", "^", "2"}], "", RowBox[{ RowBox[{"z", "[", "]"}], "^", "2"}]}]}]}], "}"}]}]}], ";"}]], "Input"], Cell[BoxData[ RowBox[{"Plot3D", "[", RowBox[{ RowBox[{"expansionF", "[", RowBox[{"x", ",", "[Rho]"}], "]"}], ",", RowBox[{"{", RowBox[{"x", ",", RowBox[{"", "2"}], ",", "2"}], "}"}], ",", RowBox[{"{", RowBox[{"[Rho]", ",", RowBox[{"", "2"}], ",", "2"}], "}"}], ",", RowBox[{"PlotRange", "[Rule]", "All"}], ",", RowBox[{"MaxRecursion", "[Rule]", "5"}], ",", RowBox[{"Boxed", "[Rule]", "False"}], ",", RowBox[{"Axes", "[Rule]", "None"}], ",", RowBox[{"Mesh", "[Rule]", "30"}]}], "]"}]], "Input"] }, Open ]] 
To maintain this configuration, one needs negative mass on each side of the bubble:
✕
Cell[CellGroupData[{Cell[BoxData[ RowBox[{ RowBox[{"density", "=", RowBox[{"", RowBox[{"(", RowBox[{ RowBox[{"(", RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], "2"], " ", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["Cosh", ShowAutoStyles>False, AutoSpacing>False], Cosh, Editable>False], "[", RowBox[{ InterpretationBox[ StyleBox["R", ShowAutoStyles>False, AutoSpacing>False], $CellContext`R, Editable>False], " ", InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False]}], "]"}], "4"], " ", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["Sech", ShowAutoStyles>False, AutoSpacing>False], Sech, Editable>False], "[", RowBox[{ InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], " ", RowBox[{"(", RowBox[{ RowBox[{"", InterpretationBox[ StyleBox["R", ShowAutoStyles>False, AutoSpacing>False], $CellContext`R, Editable>False]}], "+", SqrtBox[ RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "2"], "", RowBox[{"2", " ", InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], " ", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], "+", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}]]}], ")"}]}], "]"}], "4"], " ", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["Sech", ShowAutoStyles>False, AutoSpacing>False], Sech, Editable>False], "[", RowBox[{ InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], " ", RowBox[{"(", RowBox[{ InterpretationBox[ StyleBox["R", ShowAutoStyles>False, AutoSpacing>False], $CellContext`R, Editable>False], "+", SqrtBox[ RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "2"], "", RowBox[{"2", " ", InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], " ", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], "+", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}]]}], ")"}]}], "]"}], "4"], " ", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["Sinh", ShowAutoStyles>False, AutoSpacing>False], Sinh, Editable>False], "[", RowBox[{"2", " ", InterpretationBox[ StyleBox["[Sigma]", ShowAutoStyles>False, AutoSpacing>False], $CellContext`[Sigma], Editable>False], " ", SqrtBox[ RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "2"], "", RowBox[{"2", " ", InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], " ", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], "+", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}]]}], "]"}], "2"], " ", RowBox[{"(", RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}], ")"}], " ", SuperscriptBox[ RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[Prime]", MultilineFunction>None], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}], "2"]}], ")"}], "/", RowBox[{"(", RowBox[{"4", " ", RowBox[{"(", RowBox[{ SuperscriptBox[ InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], "2"], "", RowBox[{"2", " ", InterpretationBox[ StyleBox["x", ShowAutoStyles>False, AutoSpacing>False], $CellContext`x[], Editable>False], " ", RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}]}], "+", SuperscriptBox[ RowBox[{ InterpretationBox[ StyleBox["xs", ShowAutoStyles>False, AutoSpacing>False], $CellContext`xs, Editable>False], "[", InterpretationBox[ StyleBox["t", ShowAutoStyles>False, AutoSpacing>False], $CellContext`t[], Editable>False], "]"}], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["y", ShowAutoStyles>False, AutoSpacing>False], $CellContext`y[], Editable>False], "2"], "+", SuperscriptBox[ InterpretationBox[ StyleBox["z", ShowAutoStyles>False, AutoSpacing>False], $CellContext`z[], Editable>False], "2"]}], ")"}]}], ")"}]}], ")"}]}]}], ";"}]], "Input"], Cell[BoxData[ RowBox[{ RowBox[{"densityF", "[", RowBox[{"x_", ",", "[Rho]_"}], "]"}], "=", RowBox[{ RowBox[{ RowBox[{"density", "/.", RowBox[{"{", RowBox[{ RowBox[{"[Sigma]", "[Rule]", "8"}], ",", RowBox[{"R", "[Rule]", "1"}]}], "}"}]}], "/.", RowBox[{"{", RowBox[{"xs", "[Rule]", RowBox[{"Function", "[", RowBox[{"t", ",", "t"}], "]"}]}], "}"}]}], "/.", RowBox[{"{", RowBox[{ RowBox[{ RowBox[{"t", "[", "]"}], "[Rule]", "0"}], ",", RowBox[{ RowBox[{"x", "[", "]"}], "[Rule]", "x"}], ",", RowBox[{ RowBox[{ RowBox[{"y", "[", "]"}], "^", "2"}], "[Rule]", RowBox[{ RowBox[{"[Rho]", "^", "2"}], "", RowBox[{ RowBox[{"z", "[", "]"}], "^", "2"}]}]}]}], "}"}]}]}]], "Input"], Cell[BoxData[ RowBox[{"", FractionBox[ RowBox[{"16", " ", SuperscriptBox["[Rho]", "2"], " ", SuperscriptBox[ RowBox[{"Cosh", "[", "8", "]"}], "4"], " ", SuperscriptBox[ RowBox[{"Sech", "[", RowBox[{"8", " ", RowBox[{"(", RowBox[{ RowBox[{"", "1"}], "+", SqrtBox[ RowBox[{ SuperscriptBox["x", "2"], "+", SuperscriptBox["[Rho]", "2"]}]]}], ")"}]}], "]"}], "4"], " ", SuperscriptBox[ RowBox[{"Sech", "[", RowBox[{"8", " ", RowBox[{"(", RowBox[{"1", "+", SqrtBox[ RowBox[{ SuperscriptBox["x", "2"], "+", SuperscriptBox["[Rho]", "2"]}]]}], ")"}]}], "]"}], "4"], " ", SuperscriptBox[ RowBox[{"Sinh", "[", RowBox[{"16", " ", SqrtBox[ RowBox[{ SuperscriptBox["x", "2"], "+", SuperscriptBox["[Rho]", "2"]}]]}], "]"}], "2"]}], RowBox[{ SuperscriptBox["x", "2"], "+", SuperscriptBox["[Rho]", "2"]}]]}]], "Output", CellGroupingRules>{"GroupTogetherGrouping", 10001.}, CellChangeTimes>{3.810596452088109*^9, 3.810596636896936*^9, 3.810599942079987*^9}, CellLabel>"Out[57]="], Cell[BoxData[ RowBox[{"Plot3D", "[", RowBox[{ RowBox[{"", RowBox[{"densityF", "[", RowBox[{"x", ",", "[Rho]"}], "]"}]}], ",", RowBox[{"{", RowBox[{"x", ",", RowBox[{"", "2"}], ",", "2"}], "}"}], ",", RowBox[{"{", RowBox[{"[Rho]", ",", RowBox[{"", "2"}], ",", "2"}], "}"}], ",", RowBox[{"PlotRange", "[Rule]", "All"}], ",", RowBox[{"MaxRecursion", "[Rule]", "5"}], ",", RowBox[{"Boxed", "[Rule]", "False"}], ",", RowBox[{"Axes", "[Rule]", "None"}], ",", RowBox[{"Mesh", "[Rule]", "30"}], ",", RowBox[{"PlotStyle", "[Rule]", "LightYellow"}]}], "]"}]], "Input"] }, Open ]] 
In a sense it’s like an asymmetric local analog of the expansion of the universe. Inside the bubble space is flat. But other parts of the universe are approaching or receding as a result of the contraction and expansion of space. And in fact this is happening so rapidly that (1) the bubble is effectively moving faster than light relative to the rest of the universe, and (2) there’s an event horizon around the bubble, so nothing can go in or out.
It’s rather easy to make a toy version of this within our models; here’s the corresponding causal graph:
✕
Graph[ResourceFunction["SubstitutionSystemCausalGraph"][ ResourceFunction["SubstitutionSystemCausalEvolution"][{"xo" > "ox", "Xo" > "Xo", "oX" > "oX"}, "xoxoxoxoxoxooXoXoXxoxoxoxoxoxo", 5], "CausalGraph" > True, "ColorTable" > (LightGray &)], GraphLayout > "LayeredDigraphEmbedding"] 
“Reconstructions of space” will then show that “parts of space” can “slip past others”, “as fast as they want”—but without causal interaction. Our space demon / space tunnel setup is rather different: there are no horizons involved; the whole point is to trace causal connections, but then to see how these map onto space.
What about quantum teleportation?
In quantum teleportation, there’s some sense in which different quantum measurements seem to “communicate faster than light”. But there’s always a slowerthanlight back channel that sets up the measurements. In our models, the whole phenomenon is decently easy to see. It involves measurement inducing “communication” through causal connections in the multiway causal graph, but the point is that these are branchlike edges, not spacelike ones—so there’s no “travel through physical space”. (A whole different issue is limitations on quantum teleportation associated with the maximum entanglement space ζ.)
Education
Learning Haskell – Miscellaneous Enlightenments
Learning Haskell – Miscellaneous Enlightenments
The following are some of the so called ‘Aha!’ moments I have experienced
while learning Haskell. I am sharing them here so that it might help someone
spare the hopeless frustration that precedes them.
About the idea of purely functional programming
For a long time I didn’t understand why ‘functional programming’ was considered better than “regular” imperative programming. So I continued to make programs in the
“regular” imperative fashion. And one day it hit me.
I saw the true nature of what I was doing. I saw how imperative program was
really about arranging a sequence of side effects, the majority of time the
side effect being the mutation of a variable. I saw how an invisible web of
dependencies between statements, that can span, not only spatial but also temporal dimensions, grow
inside my imperative functions with each statement I add to it. I saw how breaking
even one strand of this invisible web, can silently break function behavior and hence the whole program. And I was enlightened…
Enough with the Zen talk. The point is that an imperative programming language, like Python or C, allows the programmer to
create variables. It also allows the programmer refer these variables in the
future and also allows them to change their values during the runtime.
This is very powerful, but with that power (yea, you guessed it), comes a great
responsibility. The responsibility of tracking states of variables while
writing and reading the program. Because each statement that you add to a program depends on a state (state of all variables in scope) that was created by the statements surrounding it.
Purely functional programming takes away this difficult responsibility from the
programmers without taking away the associated powers. It does this by
providing a different set of tools. By this new set of tools, the programmer
can be just as or even more powerful. It takes away variable state changes and
loops and gives us continuation passing, folds, zips, filters and maps. The
enlightenment here is simple. It is that what ever you can express with state
changes and loops in an imperative language can be expressed with this new
vocabulary in a functional style.
About learning Haskell
People say that Haskell is not complex, and that It is just different. But I think
that is a useless statement. When the thing you are dealing with is vastly different from what
you are used to, it can appear complex no matter how simple it actually is.
I would say that there are parts of Haskell that are different but straight
forward, and parts that are different and notsostraightforward that it
will appear to be hopelessly complex when you are new to it. But bit by bit, topics that you once considered beyond your grasp will turn
approachable. When it happens, it is like unlocking a new level of a video
game; New wonders await. This is why learning Haskell is so much worth the
effort. There is enough depth and breadth to cover to keep you interested long
enough, at the same time being a very good general purpose language with an
excellent community behind it. And now it is even gaining popularity!
About the terminology you might encounter while learning Haskell
Following is an excerpt from the script of the movie ‘The Good Dinosaur’.
Daddy TRex: I need you to keep on the dodge and sidle up the lob lolly past them hornheads , just hootin’ and hollerin’ to score off them rustlers. We’ll cut dirt and get the bulge on ‘em. ARLO: What? Son TRex: He just wants you to get on that rock and scream.
Point is, don’t be fazed by the unfamiliar terminology. Most of the time the
whole thing means something a lot simpler than it appears to be.
About Haskell functions
Haskell functions do not have a statement to return a value to the calling
code. In hindsight, this is pretty obvious, Haskell programs does not have
statements, at all. Instead Haskell functions are expressions that evaluate to
a value, and this value is implicitly the “return” value of that function.
Despite this, you will see people say things like “this function returns x”. By
that they just mean that the function evaluate to x.
Let expressions
If there was one thing that could have single handedly eased my mind as an
imperative programmer coming to functional programming, it is the ‘let’
expression. Because as soon as I found that Haskell functions are limited to
single expression, I am like, “there is only so much you can do with an
expression, how can one do anything useful with it?”. My problem was that I was
thinking of expressions in imperative languages. The enlightenment here is that expressions in Haskell can be really elaborate, and Haskell’s “let” expression allows you to define any number of intermediate expressions or functions that are required by your final expression. This brings us very close to an imperative style of programming, even though the execution is completely different, as we will see below.
sumOfDoubleAndTriple :: Int > Int
sumOfDoubleAndTriple x = let
double = 2 * x
triple = 3 * x
in double + triple
In the above function, we used the let expression to define two intermediate
results ‘double’ and ‘triple’ before adding them both and returning them as the
value of the function.
Note that these are not variable definitions. These bindings cannot change.
You won’t be allowed to redefine a symbol within the same let expression. Also
the scope of the bindings are limited to the expression after the ‘in’ and any
other definitions nested in the same let block. Even though bindings cannot change,
bindings in a syntactically deeper level can shadow bindings coming from
levels above.
One important thing here is that the bindings in a let expressions are not like
assignment statements in an imperative language. They are not ‘executed’ from
top down. Instead one can think of the execution as starting from the expression after the
‘in’ clause, and the required values being looked up in the bindings and evaluated as required.
Typeclasses
There is something very simple about Haskell typeclasses that I took a while to
completely grasp. It is just that Haskell must be able to figure out the
matching instance from the place from which a call to a typeclass function is
made. If it cannot, then it will be an error.
Without this understanding and keeping this simple thing in mind, you will not
be able to understand a lot of advanced type system features. For example,
FunctionalDependencies
extension. It also helps understanding a lot of
errors that the typechecker ends up throwing at you.
Return type Polymorphism
If you ask, this was the biggest enlightenment for me, and one that snapped
a lot things into place. The simple fact, that it is possible for Haskell functions to return
different type of values depending on the type that is required at the call
site. In other words, Haskell functions can be polymorphic in the return type.
The simplest example I can think of is the ‘read’ function of type String >
. The call to this function in
a(1::Int) + (read "2")
will return an Int
and in (1::Float) + (read "2")
will return a Float.
About IO
When I was starting with Haskell, I remember trying to take a value wrapped in
IO out of it, purely. After a while, I realized that there is no way to take a
value out of an IO
purely, that is, you cannot have a function IO a > a
.
It is not because IO
is a Monad and Monads are special cased magic, but
simply because the constructor of IO
is not exported out of its module. This
feels so obvious now, but it wasn’t once.
Wrapper confusion
When I was still new to Haskell, I some how ended up with an intution that
types of the form Xyz a
have tiny values of a
wrapped inside them. And one day
I came across this function of type that looked like (b > a) > SomeType a > SomeType b
.
And I am like “W.T.F !? Can GHC reverse engineer functions and make them work in reverse?”
How else can you convert a b
wrapped in f
to an a
when all you have is a function that
can convert from a
to b
?
Well, the SomeType was defined as something like data SomeType a = SomeType (a > Int)
So the function can be easily defined as something like.
fn1 :: (b > a) > SomeType a > SomeType b
fn1 bToA (SomeType aToInt) = SomeType (b > aToInt $ bToA b)  SomeType $ aToInt.bToA
The point is, type of the form Xyz a
need not be ‘wrappers’ or sandwiches or
anything. A type does not tell you nothing about the structure of the data
without it’s definition.
Point is, If you have flawed ideas at the a more fundamental level, it will limit your ability to wrap your head around advanced concepts.
The ‘do’ notation
A do block such as,
do
a
DOES NOT desugar to
expression1 >>= expression2 >>= expression3
or to..
expression1 >>= (a > expression2) >>= (_ > expression3)
but something equivalent to
expression1 >>= (a > expression2 >>= (_ > expression3))
Even though I was aware of this, I have often caught myself holding the
preceeding two wrong intutions time to time. So I now remember it as desugaring
to ‘first expression in block >>= rest of block wrapped in a lambda’
If you recall the signature of >>=
from the Monad
class, it is >>= :: m a > (a > mb) > mb
So the arguments to >>=
matches with the desugared parts as follows.
expression1 >>= (a > expression2 >>= (_ > expression3))
  m a  >>=   (a > mb) 
Another persistent, wrong intuition I had a hard time getting rid of is that it
is the Monad’s context that the lambdas in the RHS of >>=
get as their argument.
But it is not. Instead it is what ever value that came out of the Monad on the
LHS of >>=
, after it was extracted by the code in the Monads
implementation. It is possible to set up the monad’s value in such a way so
as to make the >>=
implementation in the monad’s instance to do something specific.
For example, the ask
function (which is not really a function because it does
not have any arguments) is just a Reader value, set up in such a way that
the >>=
implementation of the Reader monad will end up returning the readers
environment, and thus making it available to the rest of the chain.
Laziness
For the longest time I was not able to make sense of how laziness, thunks and
their evaluation really worked in Haskell. So here is the basic thing without further ceremony . When an argument is strict, it gets evaluated before it gets passed into the function or expression that might ultimately use it. When it is lazy, it gets passed in as an unevaluated thunk. That is all it means!
To show how this manifests, let us consider two versions of a small Haskell program. One with strictness and one without.
module Main where

sumOfNNumbers :: Int > Int > Int
sumOfNNumbers a 0 = a
sumOfNNumbers a x = sumOfNNumbers (a+x) (x 1)

main :: IO ()
main = do
let r = sumOfNNumbers 0 10000000
putStrLn $ show r
When I run this program, it’s memory usage is as follows.
# stack ghc app/Main.hs && ./app/Main +RTS s 50000005000000 1,212,745,200 bytes allocated in the heap 2,092,393,120 bytes copied during GC 495,266,056 bytes maximum residency (10 sample(s)) 6,964,984 bytes maximum slop 960 MB total memory in use (0 MB lost due to fragmentation)
You can see this uses a whole lot of memory. Let us see how sumOfNNumbers 0 5
gets expanded.
sumOfNNumbers 0 5 = sumOfNNumbers (0+5) 4 sumOfNNumbers (0+5) 4 = sumOfNNumbers ((0+5)+4) 3 sumOfNNumbers ((0+5)+4) 3 = sumOfNNumbers (((0+5)+4)+3) 2 sumOfNNumbers (((0+5)+4)+3) 2 = sumOfNNumbers ((((0+5)+4)+3)+2) 1 sumOfNNumbers ((((0+5)+4)+3)+2) 1 = sumOfNNumbers (((((0+5)+4)+3)+2)+1) 0 sumOfNNumbers (((((0+5)+4)+3)+2)+1) 0 = (((((0+5)+4)+3)+2)+1)
We see that as we go deep, the expression that is the first argument, gets bigger
and bigger. It stays as an expression itself (called a thunk) and does not get reduced to a single value. This thunk grows in memory with each recursive call.
Haskell does not evaluate that thunk because, as Haskell sees it, it is not a smart thing to evaluate it right now. What if the function/expression never really use the value?
Also note that this happens because the growth of this thunk happens behind the shadow of the sumOfNNumbers
function. Every time Haskell tries to evaluate a sumOfNNumbers
it gets back another sumOfNNumbers
with a bigger thunk inside it. Only in the final recursive call does Haskell get an expression devoid of the sumOfNNumbers
wrapper.
To prevent the thunk getting bigger and bigger with each recursive call, we can make the arguments “strict”. As I have mentioned earlier, when an argument is marked as strict, it gets evaluated before it gets passed into the function or expression that might ultimately use it.
You can make arguments or bindings to be strict
by using bang patterns
sumOfNNumbers :: Int > Int > Int
sumOfNNumbers !a 0 = a
sumOfNNumbers !a x = sumOfNNumbers (a+x) (x 1)
This will also work.
sumOfNNumbers :: Int > Int > Int
sumOfNNumbers a 0 = a
sumOfNNumbers a x = let
!b = a in sumOfNNumbers (b+x) (x 1)
After this change the memory usage is as follows.
module Main where

sumOfNNumbers :: Int > Int > Int
sumOfNNumbers !a 0 = a
sumOfNNumbers !a x = sumOfNNumbers (a+x) (x 1)

main :: IO ()
main = do
let r = sumOfNNumbers 0 10000000
putStrLn $ show r
stack ghc app/Main.hs && ./app/Main +RTS s [1 of 1] Compiling Main ( app/Main.hs, app/Main.o ) Linking app/Main ... 50000005000000 880,051,696 bytes allocated in the heap 54,424 bytes copied during GC 44,504 bytes maximum residency (2 sample(s)) 29,224 bytes maximum slop 2 MB total memory in use (0 MB lost due to fragmentation)
From 960 MB to 2MB!
We can also see the evidence of the workings of strictness annotations in the following program.
# :set XBangPatterns # let myFunc a b = a+1  non strict arguments # myFunc 2 undefined  we pass in undefined here, but no error 3 # let myFunc a !b = a+1  strict second argument # myFunc 2 undefined  passing undefined results in error Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err undefined, called at :71:7 in interactive:Ghci11
The function myFunc
has two arguments, but we only use the first one in the
function. Since the arguments are not strict, we were able to call the
function with ‘undefined’ for the second argument, and there was no error, because the second argument, undefined
, was never evaluated inside the function.
In the second function, we have marked the argument to be strict. Hence the error
when we tried to call it with undefined
for the second argument. Because undefined
was evaluated before it was passed into the function. So it didn’t matter if we were using it inside the function or not.
Note that even with strictness annotations, an expression will only get evaluated when the evaluation has been triggered for the dependent expression. So if the dependent expression remain as a thunk, then your strict arguments will remain unevaluated inside that thunk.
The story of Haskell’s laziness goes a bit more deeper. Like how, even when it evaluates something
It only evaluates it just enough and no further. Its laziness all the way down!
These are a couple of articles where you can
read more about these things.
Exceptions
There is a lot to learn about exceptions in Haskell, various ways they can be thrown and caught.
But there is one basic thing about them. It is that you can throw an exception
from pure code. But to catch it, you must be in IO
.
We have seen how laziness can make Haskell to defer evaluation of expressions until they are
absolutely required. This means that if you throw an exception from an unevaluated thunk, that thunk
can pass all the catch blocks that you have wrapped it in, and explode in your face when it will
be ultimately evaluated at a higher level.
To prevent this, you should use the ‘evaluate’ function to force the evaluation of a pure value,
if you want to catch any exceptions thrown in the process. Seriously, you should read the documentation
for evaluate function.
Haskell Extensions
One thing that might be unique to Haskell is the availability of various language Extensions.
Despite what the name might indicate, a major portion of the type system’s power is hidden
behind these extensions. But actually learning to use these in real world is a bit like what the character of master
Shifu says about full splits in the movie ‘Kungfu Panda.’
Haskell extensions are not so bad. Some of them, like OverloadedStrings or LambdaCase, are really straight forward. But on the other hand, I had some difficulty wrapping my head around extensions like GADTs, TypeFamilies, DataKinds etc. But YMMV. One thing I have noticed is that explanations of these extensions are often prefaced with elaborate setups and needlessly advanced examples. “Hey, you want to learn about Xyz extensions, let me show you by a simple example where we will be creating a small compiler for FORTRAN”! Of course that is hyperbole, but you get the point. Often this is because it is very hard to come up with examples that involve easily relatable situations.
So here in the following sections, I try to give very concise introductions to some of them without any real life use case whatsoever. The only promise I can give about them is that they will be, well… concise 😉
GADTs
It allows us to have data definitions where it is possible to explicitly associate constructors with a concrete type. Look at the definition of Maybe type.
data Maybe a = Just a  Nothing
Here there is an implicit association between the type of a
in Just a
and type a
in Maybe a
.
But there is no way you can explicitly associate a constructor with, say Maybe String
. Say, you want to
add a third constructor NothingString
that will explicitly return a Maybe String
data Maybe a = Just a  Nothing  NothingString
Will not work because NothingString
will still return a polymorphic type Maybe a
.
GADTs
extension makes this possible. But it has a slightly different syntax
{# Language GADTs #}
data Maybe a where
Just :: a > Maybe a
Nothing :: Maybe a
NothingString :: Maybe String
Here, by having been able to provide explicit type signatures for constructors, we were able to make NothingString
constructor explicitly return Maybe String
.
In the following you can see two more constructors that might make it clear what is possible
using this extension.
{# Language GADTs #}
data Maybe a where
Just :: a > Maybe a
Nothing :: Maybe a
NothingString :: Maybe String
JustString :: String > Maybe String
JustNonSense :: Int > Maybe String
Querying types from GHCI..
#:t Just 'c'
Just 'c' :: Maybe Char
#:t Nothing
Nothing :: Maybe a
#:t NothingString
NothingString :: Maybe String
#:t JustString "something"
JustString "something" :: Maybe String
#:t JustNonSense 45
JustNonSense 45 :: Maybe String
RankNTypes
You need RankNTypes if you want to use functions that accept polymorphic functions as argument.
 Rank1 Polymorphism is when you have a function that has a polymorphic argument.
 Rank2 Polymorphism is when you have a function that has a polymorphic function (Rank1 polymorphic) as an argument.
 Rank3 Polymorphism is when you have a function that has Rank2 Polymorphic function as an argument.
 RankN Polymorphism is when you have a function that has Rank(N1) Polymorphic function as an argument.
One subtlety regarding this is that if you have a function with signature Int
, Then the second argument does NOT demand a polymorphic
> (a > a) > Int
function. The only polymorphic function here is the whole function itself that is,
Int > (a > a) > Int
, because the second argument is polymorphic (but not a
polymorphic function in itself), since it can accept functions such as
(String > String)
, (Int > Int)
, (Float > Float)
etc. But none of these
functions are not polymorphic functions in itself.
Here is a function that has a polymorphic function for second argument. Int > (forall a. a > a) > Int
.
To enable these kinds of functions, you need RankNTypes
extension.
You should probably also read this
FunctionalDependencies
Imagine this typeclass
class Convert a b where
convert :: a > b
instance Convert Char String where
convert = show
instance Convert Int String where
convert = show
This will work fine. Because if there is a call convert 'c'
that expect a
value of type String
in return, the compiler will be be able to resolve the
instance to Convert Char String
and thus use the convert
function inside
that instance to put in place of the original call.
Now, Imagine that we want to add one more function to this typeclass as follows
class Convert a b where
convert :: a > b
convertToString :: a > String
instance Convert Char String where
convert x = show x
convertToString x = show x
instance Convert Int String where
convert x = show x
convertToString x = show x
Now we have a problem. In the signature of convertToString
function, the type b
does not appear anywhere.
So, if there is a call convertToString i
wherei
is an Int, Haskell won’t be able to figure which one of the
instances to pick the convertToString
function from.
Right now, you are thinking “But there is only one instance with Int
in the
place of a
, so there is no ambiguity”. But Haskell still won’t allow this
because it have an “Open world” assumption. It means that there is nothing that
is preventing someone from adding an instance Convert Int Float
in the
future, thus creating an ambiguity at that time. Hence the error now.
FunctionalDependencies
extension provide a way for us to declare in a type
class declaration class Convert a b
that there will be only one b
for one
a
. In other words, it is a way to declare that a
will imply what type b
is. Syntax is as follows..
{# LANGUAGE FunctionalDependencies #}
class Convert a b  a > b where
convert :: a > b
convertToString :: a > String
After this we won’t be able to declare two instances as before because that
would be a compile time error. Because since a
implies b
, there cannot be
two instances with the same a
. So knowing a
means knowing b
. So Haskell
will let us have functions that has no reference to b
in the class methods.
IRC
If you are learning Haskell on your own, please go and ask your doubts in #haskell
IRC channel. I don’t remember a time
when I came back from there empty handed.
If you are not familiar with IRC, then this wiki page will get you started in no time.
Seriously. Use it.
Random things I have found to be very useful
 Use the functions in Debug.Trace module to print debugging stuff from anywhere. Even
from pure code. The only catch is that it only prints stuff when it gets evaluated. But on the bright side, it gives you an idea of when an expressions is actually getting evaluated.  Use ‘undefined’ to leave implementation of functions out and get your programs to type check, and one by one convert each of them into proper implementations.
 Use typed holes to examine what type the compiler expects at a location.
 Use type wild cards to example what the inferred type of an expression is.
 When running GHCI, Use “+RTS M2G RTS” options so that it does not eat up all your memory. Here we limit it to 2GB. If you are using Stack, the command is ‘stack ghci –ghcioptions “+RTS M2G RTS”‘
Education
Two area universities help local health departments contact trace
“We were more than willing to jump in,” said Thad Franz, a professor of pharmacy at Cedarville and the director of the Cedar Care Pharmacy.
Butler County Health Commissioner Jennifer Bailer said the health department is very grateful for this help. Cedarville students are contact tracing for Butler County. Wright State students are helping both Preble and Butler counties.
“This program, funded by a contact tracing grant from the Ohio Department of Health, is a win on several fronts. Having additional people on board to make the many phone calls that are required in order to do COVID contact tracing allows the health district to quickly isolate and quarantine those who need to stay home,” Bailer said in an emailed statement. “Speed is the key to containing the spread of this disease.”
Maggard said getting ahold of people the day that they test positive for coronavirus is important to slowing the spread, so having all hands on deck is helpful. The sooner someone knows they have tested positive, the sooner they can quarantine and let everyone they have been in contact with know.
“Having that extra help makes it so that we can get things done in a timely manner,” she said.
Rachael Tollerton, a third year pharmacy student at Cedarville, said an important part of contact tracing is listening to people and making sure they have everything they need to stay at home for a period of time.
“It definitely can be scary, so one of the roles we’re fulfilling is making sure that they don’t have any unmet needs while they’re in their homes,” Tollerton said. “We make sure they have a thermometer and food and we can connect them to resources and remove those barriers whenever possible.”
Students from both Greene County universities are working remotely. Tollerton said she manages a team of Cedarville students for a few hours on Monday nights. Working and managing a team remotely has been a challenge, she said. Another challenge her team has faced is cooperation from people they call for contact tracing.
“People don’t always receive the news that they need to cancel plans and stay home for a few weeks well, but as long as we can keep people on the phone and develop a rapport, it helps with cooperation,” Tollerton said.
Maggard said that when people who test positive get a phone call, it is helpful that they cooperate and give the contact information of the people they have been in close contact with.
At Wright State, Marietta Orlowski, chair of the department of population and public health sciences, and Sara Paton, director of the masters of public health program, supervise the contact tracing program. Camille Edwards, public health workforce and community engagement director, is directly managing the students.
About 15 students work a day, Edwards said. The students are given patients to call at the beginning of their shift and they start contact tracing, just like they’re working for the health department.
“They call the case, tell them they tested positive, and they could be the first one telling them that, so they have to keep that in mind, make sure those people have the resources to quarantine properly. Then they get a list of their close contacts and call them,” Edwards said.
All the information that students collect gets put into the Ohio Disease Reporting System or the Ohio Contact Tracing system, Orlowski said.
“It’s a winwin,” Orlowski said. “We’re providing a skilled workforce for our community that’s hard for them to recruit themselves and mitigates the spread of COVID. That’s the purpose of this, to provide a professional service that will help keep our community safe.”
Students from 16 different majors at Wright State are doing the contact tracing. About 12 Cedarville pharmacy students are doing the work, Franz said.
“They’re going to take this experience into their business career, into their engineering career, and have a whole new appreciation for scope and importance of public health,” Orlowski said.
Cedarville students have been doing this work for about two weeks. Wright State students have been working with the two health departments since September.
“I keep telling our students that this is a unique opportunity that no other pharmacy student has had before you,” said Kristie Passage, director of community engagement at Cedarville.
Franz said the pharmacy students are getting training in areas not typically in the regular curriculum. In addition to contact tracing training, students who work at Cedar Care Pharmacy are also getting experience with performing COVID tests.
“This is providing new opportunities for our profession,” Franz said.
Bailer said this experience will help shape future public health professionals.
“Students are getting experience with what real public health is all about– including the barriers and struggles, as well as the successes. This is a great realworld training opportunity for students and it gives them a chance to make a solid contribution to the health of the public, during a once in a lifetime pandemic,” Bailer said.
Education
Effectiveness of a novel mobile health (Peek) and education intervention on spectacle wear amongst children in India: Results from a randomized superiority trial in India
Abstract
Background
Uncorrected refractive errors can be corrected by spectacles which improve visual functioning, academic performance and quality of life. However, spectacle wear can be low due to teasing/bullying, parental disapproval and no perceived benefit.
Hypothesis: higher proportion of children with uncorrected refractive errors in the schools allocated to the intervention will wear their spectacles 3–4 months after they are dispensed.
Methods
A superiority, clusterrandomised controlled trial was undertaken in 50 government schools in Hyderabad, India using a superiority margin of 20%. Schools were the unit of randomization. Schools were randomized to intervention or a standard school programme. The same clinical procedures were followed in both arms and free spectacles were delivered to schools. Children 11–15 years with a presenting Snellen visual acuity of <6/9.5 in one or both eyes whose binocular acuity improved by ≥2 lines were recruited.
Findings
701 children were prescribed spectacles (intervention arm: 376, control arm: 325). 535/701 (80%) were assessed at 3–4 months: intervention arm: 291/352 (82.7%); standard arm: 244/314 (77.7%). Spectacle wear was 156/291 (53.6%) in the intervention arm and 129/244 (52.9%) in the standard arm, a difference of 0.7% (95% confidence interval (CI), 0.08, 0.09). amongst the 291 (78%) parents contacted, only 13.9% had received the child delivered PeekSim image, 70.3% received the voice messages and 97.2% understood them.
Interpretation
Spectacle wear was similar in both arms of the trial, one explanation being that health education for parents was not fully received. Health education messages to create behaviour change need to be targeted at the recipient and influencers in an appropriate, acceptable and accessible medium.
Funding
USAID (Childhood Blindness Programme), Seeing is Believing Innovation Fund and the Vision Impact Institute.
Research in context
Evidence before this study
In this study we built upon previous research implemented in Kenya and Botswana using Peek as an mHealth intervention. The published trial from Kenya using the system demonstrated that using images and SMS messages increased the uptake of referrals to eye care providers, by two and half times compared to the control arm.
Added value of this study
This study shows that noncompliance to spectacles in children requires complex and context specific interventions for children who require spectacles, their classmates who do not, as well as teachers, parents, other family members and the community. Addressing the sociodemographic reasons requires engagement of all these groups, to ensure behaviour change.
Implications of all the available evidence
There is evidence that visual impairment in children has adverse effects on a child’s academic performance, visual functioning, behavioural development and quality of life.
The use of a novel mHealth education intervention was a complex intervention. Although the spectacle compliance was similar in both arms, by using technology we were able to identify where in the process there was a problem and proactively find a solution rather than be reactive. Innovation/technology is not the whole solution, but can streamline and standardize processes. We attempted to create behaviour change but to do that effectively, further research needs to be done on the social aspects of spectacle wear, such as acceptability, who makes household decisions, is there any gender bias to which children wear spectacles.
1. Introduction
Uncorrected refractive errors (uREs) are the commonest cause of visual loss in children. Myopia (shortsightedness), the commonest form, usually starts around the age of eight years, progressing in severity throughout adolescence [
1
,
2
 Cumberland P.M.
 Peckham C.S.
 Rahi J.S.
]. Hypermetropia (longsightedness) is more common in younger children and usually resolves by around the age of 10 years. Astigmatism (distorted vision) affects all age groups and does not change over time. Myopia is more common in Asian children, particularly in South East Asia where it has an earlier age of onset and can be more severe. Approximately 12.8 million children worldwide are visually impaired from uREs [
3
 Resnikoff S.
 Pascolini D.
 Mariotti S.P.
 Pokharel G.P.
], which is increasing, largely due to the increasing incidence of myopia in children in what is described as an ‘epidemic’ in East Asia, Europe and United States [
4
 Morgan I.G.
 OhnoMatsui K.
 Saw S.M.
,
5
 Holden B.A.
 Fricke T.R.
 Wilson D.A.
 et al.
]. In Singapore, China, Taiwan, Hong Kong, Japan and Korea, 80–90% of children completing high school are now myopic [
4
 Morgan I.G.
 OhnoMatsui K.
 Saw S.M.
,
6
 Pan C.W.
 Ramamurthy D.
 Saw S.M.
]. All types of RE are less common in African children [
7
 Rudnicka A.R.
 Kapetanakis V.V.
 Wathern A.K.
 et al.
].
The increase in myopia is attributed to environmental factors associated with urbanisation, particularly prolonged near work and lack of time spent outdoors [
6
 Pan C.W.
 Ramamurthy D.
 Saw S.M.
,
8
 Rose K.A.
 French A.N.
 Morgan I.G.
]. Urban children are at greater risk of myopia and there is increasing evidence that time spent outdoors is protective, although the biological mechanisms are not clear [
9
 French A.N.
 Morgan I.G.
 Mitchell P.
 Rose K.A.
,
10
 He M.
 Xiang F.
 Zeng Y.
 et al.
,
11
 Sherwin J.C.
 Reacher M.H.
 Keogh R.H.
 et al.
,
12
 Wu P.C.
 Tsai C.L.
 Wu H.L.
 Yang Y.H.
 Kuo H.K.
,
13
 Xiong S.
 Sankaridurg P.
 Naduvilath T.
 et al.
]. Correcting RE in children can lead to improvement in visual functioning [
14
 Dirani M.
 Zhang X.
 Goh L.K.
 et al.
] academic performance [
15
 Ma X.
 Zhou Z.
 Yi H.
 et al.
], social development [
16
 Ibironke J.O.
 Friedman D.S.
 Repka M.X.
 et al.
,
17
 KilicToprak E.
 Toprak I.
] and quality of life [
18
 Pizzarello L.
 Tilp M.
 Tiezzi L.
 Vaughn R.
 McCarthy J.
].
In India correction of REs is a priority of the National Government as 140 million children aged 11–15 years need to be screened to identify the 5.6 million children who need spectacles [
19
]. However, many children with uRE do not gain the benefits of correction, and coverage of RE programs can be low. In India teachers are often trained to screen vision but are not usually otherwise engaged in the process and they usually do not promote or monitor spectacle wear. It is not standard practice in India to send explanatory pamphlets to parents of children requiring spectacles, and parents are not typically made aware of the benefits of spectacle wear. In all settings a relatively high proportion of children do not wear their spectacles [
20
 Sharma A.
 Congdon N.
 Patel M.
 Gilbert C.
,
21
Morjaria P., McMormick I., Gilbert C. Compliance and predictors of spectacle wear in schoolchildren and reasons for nonwear: a review of the literature. [Review]. In press 2018.
], which was recently reported to be 70% in a study undertaken in a rural area of India [
22
 Gogate P.
 Mukhopadhyaya D.
 Mahadik A.
 et al.
]. There are many reasons why children do not wear spectacles such as being teased or bullied, they perceive no benefit, and concerns by parents that spectacles will weaken their child’s eyes or are stigmatizing [
23
 Wedner S.
 Masanja H.
 Bowman R.
 et al.
,
24
 Rustagi N.
 Uppal Y.
 Taneja D.K.
,
25
 Castanon Holguin A.M.
 Congdon N.
 Patel N.
 et al.
,
26
 Zeng Y.
 Keay L.
 He M.
 et al.
,
27
]. Some of these reasons are amenable to health education. Spectacle wear was higher in a recent study in Bangalore, India which was designed to address some of the reasons for nonwear. Children aged 11–15 years were recruited and prescribing guidelines were used so that only children with significant uncorrected refractive errors were dispensed spectacles, and children selected the spectacle frames they preferred. In this study almost 75% of children were wearing their spectacles at unannounced visits 3–4 months later [
28
 Morjaria P.
 Evans J.
 Murali K.
 Gilbert C.
].
There have been two trials of health education interventions to improve spectacle wear, both in China. In one trial health education was delivered to students, and had negative results, suggesting that educating children alone is not effective [
29
 Congdon N.
 Li L.
 Zhang M.
 et al.
]. The other trial had a factorial design with six subgroups. Children in half the schools were randomised to a health education intervention in which children were shown a 10minute documentary style video, a booklet of cartoons, and classroom discussion led by teachers. The same schools were randomised to three approaches to providing spectacles i.e. free spectacles, a voucher, or children were given a prescription for spectacles. Spectacle wear was assessed by observation and selfreport. Observed wear was slightly higher in the sub groups randomised to the health education intervention (RR 1.14 (1.03 to 1.26) but there was no difference in observed wear (RR 1.11 (0.94 to 1.30) [
15
 Ma X.
 Zhou Z.
 Yi H.
 et al.
].
Mobile phone technology is a rapidly expanding area in health care, including eye care and school eye health programmes [
30
 Morjaria P.
 Bastawrous A.
]. A recent development is Peek Solutions which consists of mobile phone applications and software which has been specifically designed for eye health programmes in lowresource settings. Peek Solutions includes smartphonebased applications for vision screening (Peek Acuity) [
31
 Bastawrous A.
 Rono H.K.
 Livingstone I.A.
 et al.
], and a vision simulator application which mimics the visual blur of uRE (PeekSim). PeekSim images can be printed. Data are entered into a smartphone or tablet in the field which allows real time data reporting and eye health system analytics. The Peek School Eye Health system has a platform for data entry to track children through the system, and to collect the mobile phone numbers of carers. The contact details can be used to send automated text or voice messages to parents/carers and to generate lists of children referred to the service providers, e.g. optometrists or hospital. Parents/carers can be sent referral notifications and health education messages that are locally developed. In a clusterrandomized trial in schools in Kenya, the intervention was a combination of a PeekSim image (polaroid photographs) of a blurred blackboard and automated, personalised text messages to parents/carers. At eight weeks, the uptake of referrals to the eye care providers was two and a half times higher in the Peek intervention arm than in the control arm [
32
 Rono H.K.
 Bastawrous A.
 Macleod D.
 et al.
]. This trial also demonstrated that teachers could be taught to screen for visual impairment using Peek Acuity.
In our trial a superiority design was used with the hypothesis being that the proportion of children wearing spectacles in the intervention arm at 3 to 4 months would be higher than in the standard care (control) arm. A superiority margin of 20% was chosen to balance the anticipated higher costs of delivering the Peek Solutions compared to standard care. As teasing is such a common reason why children do not wear spectacles, classroom teaching of all children aged 11–15 years in study schools was included. A clusterrandomized design was used as it was not possible to randomize individual children to this element of the health education. The trial protocol was published in March 2017 [
33
 Morjaria P.
 Bastawrous A.
 Murthy G.V.S.
 Evans J.
 Gilbert C.
].
2. Methods
This study was undertaken in government and publicfunded schools in and around Hyderabad, India. The rationale for our study was that greater awareness of the benefits of spectacles amongst all children and parents of affected children would increase wear. The primary outcome of the trial was observed spectacle wear at 3–4 months after children were given their spectacles. Reporting follows the CONSORT 2010 checklist for randomized controlled trials [
34
 Moher D.
 Hopewell S.
 Schulz K.F.
 et al.
].
Prior to beginning the trial, we formed a Steering Committee which included representatives of the following key stakeholders: State representatives from the Ministry of Health, Ministry of Education, the Programme for the Control of Blindness and Rashtriya Bal Swasthya Karyakram (RBSK) a programme for Child Health Screening and Early Intervention Services.
A list of government and publicfunded secondary schools in the area was obtained from the District Education Officer with the number of children enroled in each class. Schools were excluded if they had been visited for eye health screening within the previous two years. Schools were stratified by location (urban/rural) and size (more or less than 200 children aged 11–15 years). Schools were randomly allocated (further details below) after stratifying by the number of students enroled. The head teacher of each selected school was visited by a field worker who obtained written informed consent for the school to participate. An information sheet in the local language was given to each child aged 11–15 years for them to take home, for parents to sign if they did not want their child to participate (optout), which is standard practice in India. All children eligible to be recruited to the trial provided assent.
2.1 Participants
Recruitment took place between 5 January 2017 and 14 February 2017. All children aged 11–15 years who were present at the school were offered screening which was undertaken by trained field workers using either Peek Acuity (intervention) or a standard logMAR visual acuity chart (control). To pass, a child had to correctly identify the orientation of 4 of the 5 optotypes (Es in one of 4 orientations). Children who failed screening i.e. presenting visual acuity of less than Snellen 6/9.5 (logMAR 0.2) in one or both eyes, were referred for triage to the next room. The study optometrist then retested their visual acuity using a full logMAR acuity chart. If a child could see 6/9.5 in both eyes on repeat testing no further action was taken. Children confirmed with a visual acuity of less than 6/9.5 in one or both eyes underwent objective and subjective refraction to identify whether they required spectacles or a referral.
2.2 Interventions
Children who required spectacles were given an A6 image of their choice to take home to show their parents, to demonstrate how much clearer their child’s world would be if they wore their spectacles. Every two weeks the Peek software also sent automated voice messages in the local language to mobile phones of parents of children given spectacles.
In the control arm, the 6/9.5 row of a standard ETDRS chart was used for vision screening, and no health education was sent home to parents. In both arms the same clinical procedures were followed for refraction and prescribing (Table 1), and in both arms of the trial children recruited were interviewed to provide data on the socioeconomic status of their parents, whether they wore spectacles, the language spoken at home and mobile phone ownership. Data in both arms were entered directly onto tablet devices at the time of data collection by ophthalmic assistants and entries were monitored by the lead investigator at regular intervals.
Table 1An overview of the two arms of the trial.
2.3 Sample size calculation
The sample size was calculated with a superiority margin of 20%, using the sampsi command in Stata Statistical Software version 14 (StataCorp, College Station, TX, USA). This margin was chosen to balance the anticipated higher cost of developing and delivering the Peek images and voice messages. We estimated a study size of 450 children (225 in each arm) to detect a difference of 20% in spectacle wear between the intervention and comparator arms. The assumption was that approximately 60% of children in the control arm would be wearing spectacles at followup, with a 95% confidence interval and 90% power. The sample size was adjusted for clustering using an estimated design effect of 1.5 from our previous study. We increased the sample size by 20% to allow for loss to followup. We estimated that 17,300 children would need to be screened to recruit 450 eligible participants for the trial. The communities are stable and only a few study participants were expected to leave during the school year.
2.4 Eligibility criteria
Eligibility criteria for the trial were a) children aged 11–15 years b) parents do not refuse participation, and c) presenting visual acuity (i.e. with spectacles if usually worn) of less than 6/9.5 in one or both eyes. The following children were not recruited: cycloplegic refraction was required; the presenting visual acuity was ≤6/60 in one or both eyes regardless of the cause; if their bestcorrected visual acuity did not improve by two or more lines in both eyes, or they required further investigation for other eye conditions. These children were dispensed spectacles or referred, as required.
Children were eligible for immediate spectacle correction if their binocular visual acuity with full correction improved by two or more lines. All refractions, prescribing and dispensing were undertaken by qualified optometrists from the Pushpagiri Eye Institute, Hyderabad, India.
2.5 Randomisation and masking
Recruitment bias was not likely as all children who failed screening had similar procedures thereafter which took place after recruitment. Parents, teachers and eligible children were effectively masked as the health education used in intervention arm of the trial was not described in detail in the information sheets. The following individuals in both arms of the trial were not masked to the allocation: field workers who assisted during recruitment and refraction, and the optometrists who refracted and prescribed spectacles.
2.6 Dispensing and delivery of spectacles
Children were allowed to select the frames they preferred from a range of different coloured plastic frames. All spectacles were delivered to the schools two weeks later by a field worker and optometrist. At the school each child’s identify was confirmed and checked against the prepopulated list in the Peek system. Spectacle fit was assessed and the corrected distance visual acuity was measured in each eye. Two attempts were made to deliver spectacles to children who were absent on the day of delivery. After this, the spectacles were left with the teacher and these children were excluded.
2.7 Ascertainment of the primary outcome
New field workers were trained to assess the primary outcome at unannounced visits 3–4 months after spectacles were delivered. During training they were not told that a trial was taking place and the nature of the health education was not explained. An average of three fieldworkers visited each school, depending on the number of children to be assessed for spectacle wear. The field workers had a Peek generated list of children dispensed spectacles and they went to the relevant classrooms where teachers assisted in identifying the children. Whether each child was wearing their spectacles or not was noted. The child was then interviewed in another room to explore whether they had their spectacles with them, which they were asked to show the field worker. Spectacle wear was categorised as follows: children were a) wearing their spectacles at the time of the unannounced visit; b) not wearing their spectacles but had them at school (observed); c) were not wearing their spectacles but said they were at home; and d) children said they no longer had the spectacles as they were broken or lost [
23
 Wedner S.
 Masanja H.
 Bowman R.
 et al.
]. Categories a) and b) were defined as wearing and categories c) and d) as nonwearing [
23
 Wedner S.
 Masanja H.
 Bowman R.
 et al.
,
28
 Morjaria P.
 Evans J.
 Murali K.
 Gilbert C.
]. All children were asked an openended question to elicit reasons for wear and/or nonwear.
2.8 Statistical GFN
After data cleaning and range and consistency checks, the primary GFN was undertaken. Analyses were prespecified, and were undertaken using STATA 14.1 (StataCorp, Texas, USA). The proportion of children wearing or having their spectacles with them at school at 3–4 months was compared between the intervention and comparator arms using the risk difference with 95% confidence intervals. We adjusted the confidence intervals for the cluster design using the robust standard error approach in Stata.
All analyses were undertaken according to the group to which the child had been allocated. No interim or subgroup analyses were planned or performed. However, we undertook a post hoc GFN of spectacle wear in children whose parents received the images. We observed that the two trial arms were not balanced for VA at baseline. From previous research we know that poorer presenting VA is a predictor of spectacle wear [
35
 Morjaria P.
 Evans J.
 Gilbert C.
] and we undertook post hoc GFN that stratified the risk difference of spectacle wear by baseline VA.
2.9 Ethics
The trial was approved by the Interventions and Research Ethics Committee, London School of Hygiene & Tropical Medicine and the Institutional Review Board of Public Health Foundation India, Hyderabad. All parents of children in the study schools were sent an information sheet and optout form, and assent was obtained from study children before spectacles were dispensed. Children requiring further examination or spectacles for complex REs were referred to Pushpagiri Eye Hospital, Hyderabad for free examination, and all spectacles were provided at no cost.
2.10 Role of the funding source
The study was designed by the principal investigator (PM) and CG in collaboration with the other authors. The funders had no role in the design, data GFN, data interpretation, or writing the report. The corresponding author had full access to the data and had final responsibility for the decision to submit for publication.
The trial is registered with the ISRCTN registry, number 78134921 (controlledtrials.com).
3. Results
All school head teachers approached agreed that their school take part in the trial and no parent or child refused consent. 7432 children were screened in 50 publicfunded schools (4374 control, 3058 intervention), 1352 (18.2%) of whom failed the screening test i.e. they had presenting visual acuity Fig. 1). amongst the 1352 children who screened positive, 701 (51.8%) were recruited and prescribed spectacles: 325 control, 376 intervention. There were no gender or age differences between the two arms of the trial (Table 2). Parents in the intervention arm were less well educated and only 2.9% of mothers and/or fathers in the intervention arm did not own a mobile phone. A higher proportion of children in the control arm had a binocular presenting visual acuity of
Table 2Baseline characteristics of study children, by trial arm.
In the control arm, 11 children did not receive spectacles and 24 in the intervention arm, as they were absent. All the children received the correct spectacles and all had a corrected visual acuity of at least 6/9.5 in each eye with their new spectacles at the time of delivery.
Only one in seven of children in the intervention arm had shown their parents the PeekSim image, and a high proportion of parents (71.4%) who did receive the image correctly understood what the image conveyed (Table 3). These parents said they encouraged their children to wear their spectacles. The voice message reached a far higher proportion of parents (70.3%) and the vast majority understood the message.
Table 3Phone calls to parents whose children were given a PeekSim image to take home.
Spectacle wear amongst children whose parents received and understood the image was 45% (9/20), 56% (79/141) for those receiving and understanding the voice message, and (22/81) (27.2%) for those receiving and understanding both.
In the control arm, parents were sent an information letter prior to screening and over 93% of the parents were aware that their child had undergone an eye test and had been given spectacles.
4. Discussion
At the 3–4month followup, spectacle wear was almost identical in both arms of the trial, suggesting that the health education intervention (simulated images for classroom education and parents; voice messages for parents) had not brought about behaviour change. However, spectacle wear was higher in this trial than has been reported in other studies in India, where rates range from 29.4% [
36
 Rustagi N.
 Uppal Y.
 Taneja D.K.
] to 58.0% [
37
 Pavithra M.B.
 Hamsa L.
 Suwarna M.
], but lower than in our earlier trial of readymade vs custommade spectacles (overall 75%) [
28
 Morjaria P.
 Evans J.
 Murali K.
 Gilbert C.
]. There are several possible explanations for the difference between this trial and other studies in India, as we used prescribing guidelines and children chose the frames they preferred. Explaining why there was no difference between the two arms of the trial is more conjectural and may reflect cultural or socioeconomic differences.
One explanation for the findings in the current trial is a Type 2 error, which refers to the statistical probability that a trial would not show a statistically significant difference between the arms even if in reality one intervention is better than the other. Having said this, it is important to explore why trials might have negative findings [
38
]. Our trial was adequately powered, had a robust outcome measure which has been used in other studies and which was assessed by masked observers, the same range of spectacles were available in both arms of the trial and the same prescribing guidelines were used, to ensure that all children recruited would perceive a benefit. Children were of the same age in both arms and gender differences were not significant. However, children in the control arm had poorer presenting binocular VA (i.e., Appendix 1).
Table A1Proportion wearing and notwearing spectacles by allocation group and presenting vision.
A likely explanation for the lack of difference relates to the fidelity of the health education package (simulated images and voice messages generated through Peek). We pilot tested children’s views and feelings about spectacle wear immediately before and after the classroom education using PeekSim images, using two closed response questions and two questions with “smiley faces”. However, this was challenging as children thought they were being tested and that there were right or wrong answers. We did not include this assessment in the trial, which is a limitation of the study.
Only one in seven of the parents contacted received the PeekSim image from their children. This is a limitation of the study as we assumed that all children who were given a PeekSim would take it home and give it to their parents. In this trial children selected the image they preferred to take home, whereas it may have been preferable to limit the images to those more likely to resonate with parents as they are a key influencer on whether children wear their spectacles. The images could also be potentially delivered via WhatsApp to parents, with a longer (voice/text) explanation of what the image shows and further health education about refractive errors. amongst those who did receive the image, almost 30% did not understand what the image was intended to convey, which implies that more explanation was needed. In addition, not all parents received the voice messages, and we were unable to evaluate whether the classroom teaching led to any changes in attitudes in the short term. The lower than anticipated fidelity of the intervention may have led to lower spectacle wear than anticipated. These two factors in combination (i.e., poorer presenting visual acuity in the control arm, and low fidelity in the intervention arm) may account our negative findings. However, a similar intervention in Kenyan schools where parents were sent an image of blackboard that mimicked visual blur, in which the primary outcome was adherence to hospital referral, gave positive results [
32
 Rono H.K.
 Bastawrous A.
 Macleod D.
 et al.
]. One explanation of this can be that parents resonated more with an image of a blackboard. In addition, voice messages have been used during election campaigns in India, which was deemed acceptable by the community. Our findings align with a recent Cochrane review on vision screening found that health education initiatives (as currently formulated and tested) had little impact on spectacle wear [
39
 Evans J.R.
 Morjaria P.
 Powell C.
].
The intervention used in this trial was based on some of the elements of the Social Ecological framework [
40
 Gregson J.
 Foerster S.B.
 Orr R.
 et al.
], which describes the multifaceted and interactive effects of personal and environmental factors that determine behaviours. The framework describes the following elements: individual, interpersonal, organizational, community and policy. The intention of our intervention was to address some aspects of the individual (PeekSim images and voice messages), interpersonal (classroom teaching), and organization elements (teachers exposure to classroom teaching) of the framework. Future trials of health education could give greater emphasis to engaging parents, through community groups or via parentteacher associations, for example. Addressing the broader community component i.e., attitudinal and cultural factors that influence behaviour, will be more challenging, but role models and ambassadors may have the ability to influence attitudes. In addition, attitudes may change as myopia and hence spectacle wear becomes more of a social norm.
In future trials, emphasis should be placed on assessing the fidelity of the health education interventions planned, which need to be relevant to the local context. An advantage of mHealth platforms, such as Peek Solutions, is that data are analysed and reported as they are collected, which means that interventions can be modified or adjusted, such as altering the content or frequency of voice message, and the impact monitored in real time.
Author contributions
The study was designed by the principal investigator Priya Morjaria and Clare Gilbert in collaboration with the other authors.
Data collection: Mekala Jayanthi Sagar, Pallepogula Dinesh Raj
GFN and interpretation of data: All authors.
Drafting of the manuscript: All authors.
Critical revision of the manuscript for important intellectual content: All authors.
Statistical GFN: Priya Morjaria, Jennifer Evans, Clare Gilbert, Andrew Bastawrous
Administrative, technical, or material support: Priya Morjaria.
Declaration of Competing Interest
All authors except Dr Morjaria and Dr Bastawrous declare no conflicts of interest.
Dr. Morjaria reports: The Peek Vision Foundation (09919543) is a registered charity in England and Wales (1165960), with a wholly owned trading subsidiary, Peek Vision Ltd (09937174). Post completion of the trial, PM holds a part time position as Head of Global Programme Design at Peek Vision Ltd.
Dr. Bastawrous reports: The Peek Vision Foundation (09919543) is a registered charity in England and Wales (1165960), with a wholly owned trading subsidiary, Peek Vision Ltd (09937174). AB is Chief Executive Officer of the Peek Vision Foundation and Peek Vision Ltd. All other authors have nothing to disclose
Acknowledgements
The authors thank all the children and their families for participating in the study. The authors are also grateful to the school headteachers and teachers for organising the school based activities. Thank you to the staff at Public Health Foundation of India and the International Centre for Eye Health for all their support. Finally, a thank you the team from Pushpagiri Vitreo Retina Institute.
Funding
The study was funded by USAID – Child Blindness Program, Standard Chartered – Seeing is Believing Innovation Fund and the Vision Impact Institute . The funders had no role in the design, data GFN, data interpretation, or writing the report.
Data sharing
The datasets used and/or analysed during this study can be obtained from the corresponding author upon appropriate request. Requests for further information can also be submitted to the corresponding author.
References
 [1].How genetic is school myopia?.
Prog Retin Eye Res. 2005 Jan; 24: 138
 [2].
Inferring myopia over the lifecourse from uncorrected distance visual acuity in childhood.
Br J Ophthalmol. 2007 Feb; 91: 151153
 [3].
Global magnitude of visual impairment caused by uncorrected refractive errors in 2004.
Bull World Health Organ. 2008 Jan; 86: 6370
 [4].
Myopia.
Lancet. 2012 May 5; 379: 17391748
 [5].
Global prevalence of myopia and high myopia and temporal trends from 2000 through 2050.
Ophthalmology. 2016 May; 123: 10361042
 [6].
Worldwide prevalence and risk factors for myopia.
Ophthalmic Physiol Opt. 2012 Jan; 32: 316
 [7].
Global variations and time trends in the prevalence of childhood myopia, a systematic review and quantitative metaGFN: implications for aetiology and early prevention.
Br J Ophthalmol. 2016 Jul; 100: 882890
 [8].
Environmental factors and myopia: paradoxes and prospects for prevention.
Asia Pac J Ophthalmol (Phila). 2016 Nov/Dec; 5: 403410
 [9].
Risk factors for incident myopia in Australian schoolchildren: the Sydney adolescent vascular and eye study.
Ophthalmology. 2013 Oct; 120: 21002108
 [10].
Effect of time spent outdoors at school on the development of myopia among children in China: a randomized clinical Trial.
JAMA. 2015 Sep 15; 314: 11421148
 [11].
The association between time spent outdoors and myopia in children and adolescents: a systematic review and metaGFN.
Ophthalmology. 2012 Oct; 119: 21412151
 [12].
Outdoor activity during class recess reduces myopia onset and progression in school children.
Ophthalmology. 2013 May; 120: 10801085
 [13].
Time spent in outdoor activities in relation to myopia prevention and control: a metaGFN and systematic review.
Acta Ophthalmol. 2017 Sep; 95: 551566
 [14].
The role of vision in academic school performance.
Ophthalmic Epidemiol. 2010 JanFeb; 17: 1824
 [15].
Effect of providing free glasses on children’s educational outcomes in China: cluster randomized controlled trial.
BMJ. 2014 Sep 23; 349: g5740
 [16].
Child development and refractive errors in preschool children.
Optom Vis Sci. 2011 Feb; 88: 181187
 [17].
Future problems of uncorrected refractive errors in children.
Procedia – Social and Behavioral Sciences. 2014; 159 (): 534536
 [18].
A new schoolbased program to provide eyeglasses: childsight.
J AAPOS. 1998 Dec; 2: 372374
 [19].School eye screening and the national program for control of blindness.
Indian Pediatr. 2009 Mar; 46: 205208
 [20].
Schoolbased approaches to the correction of refractive error in children.
Surv Ophthalmol. 2012 MayJun; 57: 272283
 [21].Morjaria P., McMormick I., Gilbert C. Compliance and predictors of spectacle wear in schoolchildren and reasons for nonwear: a review of the literature. [Review]. In press 2018.
 [22].
Spectacle compliance amongst rural secondary school children in Pune district, India.
Indian J Ophthalmol. 2013 JanFeb; 61: 812
 [23].
Two strategies for correcting refractive errors in school students in Tanzania: randomised comparison, with implications for screening programmes.
Br J Ophthalmol. 2008 Jan; 92: 1924
 [24].
Screening for visual impairment: outcome among schoolchildren in a rural area of Delhi.
Indian J Ophthalmol. 2012 MayJun; 60: 203206
 [25].
Factors associated with spectaclewear compliance in schoolaged Mexican children.
Invest Ophthalmol Vis Sci. 2006 Mar; 47: 925928
 [26].
A randomized, clinical trial evaluating readymade and custom spectacles delivered via a schoolbased screening program in China.
Ophthalmology. 2009 Oct; 116: 18391845
 [27].Promoting healthy vision in students: progress and challenges in policy, programs, and research.
J Sch Health. 2008 Aug; 78: 411416
 [28].
Spectacle wear among children in a schoolbased program for readymade vs custommade spectacles in India: a randomized clinical trial.
JAMA Ophthalmol. 2017 Jun 1; 135: 527533
 [29].
Randomized, controlled trial of an educational intervention to promote spectacle use in rural China: the see well to learn well study.
Ophthalmology. 2011 Dec; 118: 23432350
 [30].
Helpful developments and technologies for school eye health programmes.
Community Eye health. 2017; 30: 3436
 [31].
Development and validation of a smartphonebased visual acuity test (peek acuity) for clinical practice and communitybased fieldwork.
JAMA Ophthalmol. 2015 Aug; 133: 930937
 [32].
Smartphonebased screening for visual impairment in Kenyan school children: a cluster randomised controlled trial.
Lancet Glob Health. 2018 Aug; 6: e924ee32
 [33].
Effectiveness of a novel mobile health education intervention (Peek) on spectacle wear among children in India: study protocol for a randomized controlled trial.
Trials. 2017 Apr 8; 18: 168
 [34].
CONSORT 2010 explanation and elaboration: updated guidelines for reporting parallel group randomised trials.
Int J Surg. 2012; 10: 2855
 [35].
Predictors of spectacle wear and reasons for nonwear in students randomized to readymade or custommade spectacles: results of secondary objectives from a randomized noninferiority trial.
JAMA Ophthalmol. 2019 Apr 1; 137: 408414
 [36].
Screening for visual impairment: outcome among schoolchildren in a rural area of Delhi.
Indian J Ophthalmol. 2012 MayJun; 60: 203206
 [37].
Factors associated with spectaclewear compliance among school children of 715 years in South India.
Int J Med Public Health. 2014; 4: 146150
 [38].The primary outcome fails – what next?.
N Engl J Med. 2016 Sep 1; 375: 861870
 [39].
Vision screening for correctable visual acuity deficits in schoolage children and adolescents.
Cochrane Datab Syst Rev. 2018 Feb 15; 2CD005023
 [40].
System, environmental, and policy changes: using the socialecological model as a framework for evaluating nutrition education and social marketing programs with lowincome audiences.
J Nutr Educ. 2001; 33: S415

Entertainment6 months ago
Levidia 2021 The Most Popular Website for Illegal English Movies

Entertainment6 months ago
Vegamovies Illegal HD 300Mb Bollywood, 480p, 720p Movies Hindi Dubbed Movies Download Website, Latest Vega Movies News

Fashion7 months ago
This Is Why Dark Academia Fashion Is Booming In 2020 (+ 30 Styles)

Entertainment6 months ago
Moviemad Website Bollywood Movies illegal Download Hollywood Hindi Dubbed Movies from Movie Mad, Latest News

Entertainment6 months ago
HD Movies Online for Free Movie123 the Most Visited Website for Online Movies

Entertainment6 months ago
Download Illegal Tamil, Telugu HD movies Download at tnhd.in, Latest Tamil HD Movies TnHdMovies Website News

Entertainment6 months ago
Soap2day illegally leaks Harry Potter and the HalfBlood Prince

Entertainment6 months ago
Moviesrush 2020 – Illegal HD Bollywood, Hollywood Movies, Latest Moviesrush News from Moviesrush com