# 4.14 The Effect of Perturbations

Imagine that at some step in the evolution of a rule one reverses a single relation. What effect will it have? Here is an example for the rule {{x,y},{x,z}}{{x,z},{x,w},{y,w},{z,w}}. The first row is the original evolution; the second is the evolution after reversing the relation:

init = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, {{0, 0}, {0, 0}}, 5, "FinalState"]; evol = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, init, 4]["StatesPlotsList", ImageSize -> 120]
initp = {{0, 9}, {4, 10}, {0, 2}, {0, 12}, {5, 12}, {2, 12}, {3, 7}, \ {3, 13}, {6, 13}, {7, 13}, {2, 7}, {2, 14}, {6, 14}, {7, 14}, {1, 4}, \ {1, 15}, {6, 15}, {4, 15}, {0, 1}, {0, 16}, {7, 16}, {1, 16}, {4, 9}, \ {4, 17}, {8, 17}, {9, 17}, {1, 9}, {1, 18}, {18, 8}, {9, 18}, {2, \ 10}, {2, 19}, {5, 19}, {10, 19}, {1, 11}, {1, 20}, {3, 20}, {11, 20}, \ {5, 11}, {5, 21}, {10, 21}, {11, 21}, {3, 11}, {3, 22}, {8, 22}, {11, \ 22}}; evolp = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, initp, 4]["StatesPlotsList", ImageSize -> 120]

We can illustrate the effect by coloring edges in the first row of graphs that are different in the second one (taking account of graph isomorphism) [41]:

init = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, {{0, 0}, {0, 0}}, 5, "FinalState"]; evol = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, init, 4, "StatesList"]; initp = {{0, 9}, {4, 10}, {0, 2}, {0, 12}, {5, 12}, {2, 12}, {3, 7}, {3, 13}, {6, 13}, {7, 13}, {2, 7}, {2, 14}, {6, 14}, {7, 14}, {1, 4}, {1, 15}, {6, 15}, {4, 15}, {0, 1}, {0, 16}, {7, 16}, {1, 16}, {4, 9}, {4, 17}, {8, 17}, {9, 17}, {1, 9}, {1, 18}, {18, 8}, {9, 18}, {2, 10}, {2, 19}, {5, 19}, {10, 19}, {1, 11}, {1, 20}, {3, 20}, {11, 20}, {5, 11}, {5, 21}, {10, 21}, {11, 21}, {3, 11}, {3, 22}, {8, 22}, {11, 22}}; evolp = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, initp, 4, "StatesList"]; MapThread[ ResourceFunction["WolframModelPlot"][#, EdgeStyle -> <|Alternatives @@ #2 -> Directive[Thick, Red]|>, ImageSize -> 120] &, {evol, MapThread[Complement, {evol, evolp}]}]

Visualizing the second and third graphs in 3D makes it more obvious that the changed edges are mostly connected:

init = ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, { z, w}}, {{0, 0}, {0, 0}}, 5, "FinalState"]; evol = Map[Graph[ Apply[Rule, #, {1}], GraphLayout -> "SpringElectricalEmbedding", ImageSize -> 120, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]& , ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, { z, w}}, init, 4, "StatesList"]]; initp = {{0, 9}, {4, 10}, {0, 2}, {0, 12}, {5, 12}, {2, 12}, {3, 7}, { 3, 13}, {6, 13}, {7, 13}, {2, 7}, {2, 14}, {6, 14}, {7, 14}, {1, 4}, {1, 15}, {6, 15}, {4, 15}, {0, 1}, {0, 16}, {7, 16}, {1, 16}, { 4, 9}, {4, 17}, {8, 17}, {9, 17}, {1, 9}, {1, 18}, {18, 8}, {9, 18}, {2, 10}, {2, 19}, {5, 19}, {10, 19}, {1, 11}, {1, 20}, {3, 20}, {11, 20}, {5, 11}, {5, 21}, {10, 21}, {11, 21}, {3, 11}, {3, 22}, {8, 22}, {11, 22}}; evolp = Map[Graph[ Apply[Rule, #, {1}], GraphLayout -> "SpringElectricalEmbedding", ImageSize -> 120, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"]]& , ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, { z, w}}, initp, 4, "StatesList"]]; evold = MapThread[HighlightGraph[#, Map[Style[#, Thick, Red]& , #2]]& , {evol, Map[EdgeList, MapThread[GraphDifference, {evol, evolp}]]}]; Graph3D[#, ImageSize -> 270, BaseStyle -> {Graphics3DBoxOptions -> {Method -> {"ShrinkWrap" -> True}}}, VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph3D", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph3D", "EdgeLineStyle"]] & /@ evold[[{2, 3}]]

It takes only a few steps before the effect of the change has spread to essentially all parts of the system. (In this particular case, with the updating order used, about 20% of edges are still unaffected after 5 steps, with the fraction slowly decreasing, even as the number of new edges increases.)

In rules with fairly simple behavior, it is common for changes to remain localized:

sinit = ResourceFunction[ "WolframModel"][{{x, y}} -> {{x, z}, {x, z}, {z, y}}, {{0, 0}}, 2, "FinalState"]; sinitp = {{0, 2}, {0, 2}, {2, 1}, {0, 3}, {0, 3}, {1, 3}, {1, 4}, {1, 4}, {4, 0}}; sevol = Graph[Rule @@@ #, GraphLayout -> "SpringElectricalEmbedding", VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"] , ImageSize -> 120] & /@ ResourceFunction[ "WolframModel"][{{x, y}} -> {{x, z}, {x, z}, {z, y}}, sinit, 3, "StatesList"]; sevolp = Graph[Rule @@@ #, GraphLayout -> "SpringElectricalEmbedding", VertexStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "VertexStyle"], EdgeStyle -> ResourceFunction["WolframPhysicsProjectStyleData"][ "SpatialGraph", "EdgeLineStyle"], ImageSize -> 120] & /@ ResourceFunction[ "WolframModel"][{{x, y}} -> {{x, z}, {x, z}, {z, y}}, sinitp, 3, "StatesList"]; MapThread[ HighlightGraph[#, Style[#, Thick, Red] & /@ #2] &, {sevol, EdgeList /@ MapThread[GraphDifference, {sevol, sevolp}]}]

However, when complex behavior occurs, changes tend to spread. This is analogous to what is seen, for example, in the much simpler case of class 2 versus class 3 cellular automata [31][1:6.3]:

With[{u = RandomInteger[1, 100]}, SeedRandom[24245]; ArrayPlot[ Sum[(2 + (-1)^i) CellularAutomaton[#, ReplacePart[u, 50 -> i], 50], {i, 0, 1}], ColorRules -> {0 -> White, 4 -> Black, 1 -> Red, 3 -> Red}, ImageSize -> 150]] & /@ {78, 94, 22, 30}

Cellular automata are also known [31] to exhibit the important phenomenon of class 4 behaviorin which there is a discrete set of localized “particle-like” structures through which changes typically propagate:

SeedRandom[24246]; Table[ With[{u = RandomInteger[1, 400]}, ArrayPlot[ Sum[(2 + (-1)^i) CellularAutomaton[110, ReplacePart[u, 200 -> i], 300], {i, 0, 1}], ColorRules -> {0 -> White, 4 -> Black, 1 -> Red, 3 -> Red}, ImageSize -> 280]], 2]

In cellular automata, there is a fixed lattice on which local rules operate, making it straightforward [1:6.3] to identify the region that can in principle be affected by a change in initial conditions. In the models here, however, everything is dynamic, and so even the question of what parts can in principle be affected by a change in initial conditions is nontrivial.

As we will discuss at length later, however, it is always possible to trace which updating events in a particular evolution depend on which others, and which relations are associated with these. The result will always be a superset of the actual effect of a change in the initial condition:

WolframModelCausalCones[function_, evolution_, startGeneration_Integer, endGeneration_Integer, eventChoiceFunction_ : RandomChoice] := Module[{startEvent, finalGenerationEvents, toHighlight, positiveStartGeneration, positiveEndGeneration}, {positiveStartGeneration, positiveEndGeneration} = If[# >= 0, #, evolution["TotalGenerationsCount"] + # + 1] & /@ {startGeneration, endGeneration}; startEvent = eventChoiceFunction[ First /@ Position[evolution["AllEventsGenerationsList"], positiveStartGeneration]]; finalGenerationEvents = Prepend[0]@Accumulate@evolution["GenerationEventsCountList"]; toHighlight = First /@ Position[evolution["EdgeCreatorEventIndices"], Alternatives @@ VertexOutComponent[evolution["CausalGraph"], startEvent]]; function[evolution["AllEventsEdgesList"][[#]], evolution["AllEventsEdgesList"][[ Intersection[#, toHighlight]]]] & /@ (evolution[ "StateEdgeIndicesAfterEvent", #] &) /@ finalGenerationEvents[[ positiveStartGeneration + 1 ;; positiveEndGeneration + 1]]] WolframModelCausalConeSlices[evolution_, startGeneration_Integer : -4, endGeneration_Integer : -1, eventChoiceFunction_ : RandomChoice] := WolframModelCausalCones[ ResourceFunction["WolframModelPlot"][#1, GraphHighlight -> #2, ImageSize -> 120, GraphHighlightStyle -> Directive[Red, Thick]] &, evolution, startGeneration, endGeneration, eventChoiceFunction]; SeedRandom[4247]; \ WolframModelCausalConeSlices[ ResourceFunction[ "WolframModel"][{{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}}, {{0, 0}, {0, 0}}, 9], -5, -1]

We discussed above the quantity Vr(X) obtained by “statically” looking at the number of nodes in a hypergraph reached by going graph distance rin effect computing the volume of a ball of radius r in the hypergraph. By looking at the dependence of updating events in t successive steps of evolution, we can define another quantity Ct(X) which in effect measures the volume of a cone of dependencies in the evolution of the system.

Vr(X) is in a sense a quantity that is “applied” to the system from outside; Ct(X) is in a sense intrinsic. But as we will discuss later, Vr(X) is in some sense an approximation to Ct(X)and particularly when we can reasonably consider the evolution of a model to have reached some kind of “equilibrium”, Vr(X) will provide a useful characterization of the “state” of a model.