This animation was inspired by Daniel Piker and Etienne Jacob. The math behind it is explained well in this post on the n-Category Café by Simon Willerton.
One way to think about what’s going on is that the the group is acting on the plane (in the picture the plane is and , but I’m really thinking about the action on when ). This action is pretty much the simplest possible action which motivates the notion of a Geometric Invariant Theory quotient (see Thomas' very nice survey [arXiv version]): if this group acts on points of the form , then the product is conserved, so each nonzero number corresponds to an orbit which is just the hyperbola . However, there are three different orbits for which , namely the two axes (with the origin removed) and the origin itself. Unfortunately, the closures of these three orbits intersect, so the orbit space is non-Hausdorff unless we do something slightly more sophisticated. In GIT, the upshot is to identify the three orbits and then the quotient is just a copy of the line (i.e., in the complex case). We can also projectivize and think of a action on , with GIT quotient isomorphic to , as in this talk.
G=
t e | 0 |
0 | -t e |
2
t∈
2
t∈
(x,y)
xy
λ
xy=λ
xy=0
2
1
However, there’s rather more going on here. If we think of a lattice in the plane , then we can think of as acting on . Of course, this will generally change the lattice, but if we choose the lattice very carefully, we can get a periodic action: after some finite , the lattice comes back to itself (even though the individual points have of course moved). That is the modular flow, and getting the lattice right is the hard part of the visualization.
Λ
2
G
Λ
t
0
In[]:=
ColorMapSuitePath=NotebookDirectory[]<>"../colors/ScientificColourMaps7";ColorMapSuite[name_String]:=ColorMapSuite[name,-1]ColorMapSuite[name_String,el_]:=With[{list=Transpose@{Subdivide[0,1,255],RGBColor@@@First@Import[ColorMapSuitePath<>"/"<>name<>"/"<>name<>".mat"]}},Blend[list,{##}[[el]]]&]
Now, our lattice will be points of the form , where and is an integer point in the plane. Our final view will be the square , so we need to keep track of all the points that will enter that square at some point in the animation, which is what pts is doing.
P
x |
y |
P=
-1 | - 2 |
1 | - 2 |
∈
x |
y |
2
2
[-10,10]
In[]:=
P=-1,-Log-2+2;pts=SelectFlatten[Table[{x,y},{x,-30,30},{y,-30,30}],1],AbsDiagonalMatrix,.P.#[[1]]<=10.5&;
2
,1,-2
;ct[{x_,y_}]:=1
2
2
x
2
xy+22
y
2
x
2
xy+22
y
ct[#]
E
-ct[#]
E
In the final animation, the points have tails on them. Since the tails will overlap other points, we need to sort the points appropriately to make sure that the points are layered in an appropriate way.
In[]:=
sort=DeleteDuplicates[SortBy[pts,Abs[N[(P.#)][[2]]]&]];
Now we build the table of frames in the animation:
In[]:=
flow=With{cols=Append[#[[2]],#[[1]]]&/@ColorMapSuite["oslo"][[1,1]]},ParallelTableShow[Table[ParametricPlot[DiagonalMatrix[{,}].P.Append[sort,{0,0}][[i]],{s,t-.5,t},PlotRange->10,ColorFunction(If[i==Length[pts]+1,cols[[-1]],Blend[cols,2(#3-t+.5)]]&),ColorFunctionScalingFalse,Axes->False,PlotStyleDirective[Thickness[.02],CapForm["Round"]]],{i,1,Length[pts]+1}],ImageSize270,Backgroundcols[[1,;;-2]]],t,0.,2Log[1+;
s
E
-s
E
2
]-#,#&2Log[1+
2
]70.
Which we can export to a GIF:
Export[NotebookDirectory[]<>"flow.gif",flow,"AnimationRepetitions"->Infinity,"DisplayDurations"->1/50];
Or visualize directly in Mathematica using ListAnimate:
In[]:=
ListAnimate[flow,50]
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Modular Flow
by Clayton Shonkwiler
Wolfram Community, STAFF PICKS, November 7, 2023
https://community.wolfram.com/groups/-/m/t/3061781
by Clayton Shonkwiler
Wolfram Community, STAFF PICKS, November 7, 2023
https://community.wolfram.com/groups/-/m/t/3061781