Sébastien Labbé, CNRS, LaBRI, Université de Bordeaux
Conference Algebraic and Combinatorial Invariants of Subshifts and Tilings, CIRM, Marseille, January 13, 2021
These slides are available in 3 formats:
HELP for navigating in the HTML slides:
Outline as 5 sections (disposed as columns of slides if viewed in html format):
Computations (arithmetic, comparisons, etc.) are more efficient when performed in a number field like $\mathbb{Q}(\varphi)$ with $\varphi=(1+\sqrt{5})/2$.
z = polygen(QQ, 'z')
K.<phi> = NumberField(z**2-z-1, 'phi', embedding=RR(1.6)); K
Number Field in phi with defining polynomial z^2 - z - 1 with phi = 1.618033988749895?
phi.n(digits=500)
1.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374847540880753868917521266338622235369317931800607667263544333890865959395829056383226613199282902678806752087668925017116962070322210432162695486262963136144381497587012203408058879544547492461856953648644492410443207713449470495658467885098743394422125448770664780915884607499887124007652170575179788341662562494075890697040002812104276217711177780531531714101170466659914669798731761356006708748071
phi^2 + phi^-10
-54*phi + 90
vertices = [(0,0), (1,0), (0,1), (1,1/phi), (1/phi,1)]
bottom = Polyhedron(vertices)
bottom
Convention for inequalities: $7+2x_1-3x_2\geq 0$ is incoded as (7, 2, -3)
.
top = Polyhedron(ieqs=[(-1/phi-1,1,1), (1,-1,0), (1,0,-1)])
top.plot(xmin=0, ymin=0)
from slabbe import PolyhedronPartition
P = PolyhedronPartition([bottom, top])
P.plot()
square = Polyhedron([(0,0), (1,0), (0,1), (1,1)])
P = PolyhedronPartition([square])
P = P.refine_by_hyperplane([-1/phi-1,1,1])
P.plot()
from slabbe import PolyhedronExchangeTransformation as PET
lattice_base = matrix.column([(1,0), (0,1)])
T = PET.toral_translation(lattice_base, vector((phi^-2,0)))
def title(content, height=1.08, fontsize=10):
return text(content, (.5, height), fontsize=fontsize)
t1 = title(r"domain partition of $T$", fontsize=10)
t2 = title(r"image partition of $T$", fontsize=10)
graphics_array([T.partition().plot()+t1, T.image_partition().plot()+t2]).show(figsize=5)
t = title(r"$T$", fontsize=20)
(T.plot()+t).show(figsize=4)
A continuous $\Z^2$-action $\begin{array}{lcll} R_0:&\Z^2\times\T^2&\to&\T^2\\ & (\bn,\bx)&\mapsto&\bx+\varphi^{-2}\bn \bmod\Z^2 \end{array}$ can be written as a pair of commuting PETs.
R0e1 = PET.toral_translation(lattice_base, vector((phi^-2,0)))
R0e2 = PET.toral_translation(lattice_base, vector((0,phi^-2)))
t1 = title(r"$R_0^{e_1}$", fontsize=20)
t2 = title(r"$R_0^{e_2}$", fontsize=20)
graphics_array([R0e1.plot()+t1, R0e2.plot()+t2])
t1 = title(r"$R_0^{e_1}$", fontsize=15); t2 = title(r"$R_0^{e_2}$", fontsize=15); t3 = title(r"$\mathcal{P}$", fontsize=15)
graphics_array([R0e1.plot()+t1, R0e2.plot()+t2, P.plot()+t3])
Recall that the first return map $\widehat{T}|_W$ of a dynamical system $(X,T)$ maps a point $\bx\in W\subset X$ to the first point in the forward orbit of $T$ lying in $W$, i.e. $$ \widehat{T}|_W(\bx) = T^{r(\bx)}(\bx) \quad\text{ where } r(\bx) = \min\{k\in\Z_{>0} : T^k(\bx)\in W\}. $$
Facts:
please_draw_Rauzy_induction
¶This is some code to draw induced transformation on the next slide (you may safely ignore what is below).
bb = point([(0,0), (1,1)], color='white') ### hack to make all plots to have the same bounding box
def please_draw_Rauzy_induction(T, P, inducedT, inducedP, beta, figsize=9):
t1 = title(r'transformation $T$', fontsize=15)
t2 = title(r'partition $\mathcal{P}$', fontsize=15)
t3 = title(r'induced transformation $\widehat{T}|_W$', fontsize=15)
t4 = title(r'induced partition $\widehat{\mathcal{P}}|_W$', fontsize=15)
graphics_array([T.plot()+bb+t1, P.plot()+bb+t2,
inducedT.plot()+bb+t3,
inducedP.plot()+bb+t4], ncols=2).show(figsize=figsize)
show(LatexExpr(r"\text{The induced substitution is }"+
r"\beta:{}".format(latex(beta))))
x_ineq = [phi^-1, -1, 0] ### x <= phi^-1
inducedT,beta = T.induced_transformation(x_ineq)
please_draw_Rauzy_induction(T, T.partition(), inducedT, inducedT.partition(), WordMorphism(beta))
x_ineq = [phi^-1, -1, 0] ### x <= phi^-1
inducedT,_ = T.induced_transformation(x_ineq)
inducedP,beta = T.induced_partition(x_ineq, P, substitution_type='row')
please_draw_Rauzy_induction(T, P, inducedT, inducedP, beta)
Of course, for general subdomain $W$, the induced transformation $\widehat{T}|_W$ of a toral rotation $T$ is not a toral rotation. Today, the induced transformations are toral rotations, so they commute between themselves.
x_ineq = [phi^-1+1/10, -1, 0-1/5]
inducedT,_ = T.induced_transformation(x_ineq)
inducedP,beta = T.induced_partition(x_ineq, P, substitution_type='row')
please_draw_Rauzy_induction(T, P, inducedT, inducedP, beta)
The polygon partition $P_a$:
square = Polyhedron([(0,0), (1,0), (0,1), (1,1)])
Pa = PolyhedronPartition([square])
Pa = Pa.refine_by_hyperplane([-1/phi, 0, 1])
Pa.plot()
The polygon partition $P_b$:
Pb = PolyhedronPartition([square])
Pb = Pb.refine_by_hyperplane([-1/phi, 1, 0])
Pb = Pb.refine_by_hyperplane([-1/phi^2, 1, 0])
Pb.plot()
The polygon partition $P_c$:
Pc = PolyhedronPartition([square])
Pc = Pc.refine_by_hyperplane([-1,1,1])
Pc = Pc.refine_by_hyperplane([-1/phi^2,1,1])
Pc = Pc.refine_by_hyperplane([-1/phi^2-1,1,1])
Pc.plot()
The polygon partition $P_d$:
Pd = PolyhedronPartition([square])
Pd = Pd.refine_by_hyperplane([-1,phi,1])
Pd = Pd.refine_by_hyperplane([-1/phi,phi,1])
Pd = Pd.refine_by_hyperplane([-1/phi-1,phi,1])
Pd.plot()
The polygon partitions $P_a$, $P_b$, $P_c$, $P_d$ and their refinement:
graphics_array([Pa.plot(), Pb.plot(), Pc.plot(), Pd.plot()]).show(figsize=8)
Pa.refinement(Pb).refinement(Pc).refinement(Pd).plot()
The partition $\Pcal_\Ucal$ using the labelling defined in arXiv:1903.06137
from slabbe.arXiv_1903_06137 import self_similar_19_atoms_partition
P0 = PU = self_similar_19_atoms_partition()
P0.plot()
A continuous $\Z^2$-action $R_0$ on $\T^2$: $\begin{array}{lcll} R_0:&\Z^2\times\T^2&\to&\T^2\\ & (\bn,\bx)&\mapsto&\bx+\varphi^{-2}\bn \bmod\Z^2 \end{array}$
lattice_base = matrix.column([(1,0), (0,1)])
R0e1 = PET.toral_translation(lattice_base, vector((phi^-2,0)))
R0e2 = PET.toral_translation(lattice_base, vector((0,phi^-2)))
t1 = title(r"$R_0^{e_1}$", fontsize=20)
t2 = title(r"$R_0^{e_2}$", fontsize=20)
graphics_array([R0e1.plot()+t1, R0e2.plot()+t2])
please_draw_Rauzy_induction_for_Z2_action
¶This is some code to draw induced transformation on the next slide (you may safely ignore what is below).
def please_draw_Rauzy_induction_for_Z2_action(T1, T2, P, inducedT1, inducedT2, inducedP, beta,
subscripts=['',''],figsize=9, fontsize=15):
input_subscript, output_subscript= subscripts
t1 = title(r'$R^{e_1}%s$'%input_subscript, fontsize=fontsize)
t2 = title(r'$R^{e_2}%s$'%input_subscript, fontsize=fontsize)
t3 = title(r'$\mathcal{P}%s$'%input_subscript, fontsize=fontsize)
t4 = title(r'$R^{e_1}%s:=\widehat{R^{e_1}%s}|_W$'%(output_subscript, input_subscript), fontsize=fontsize)
t5 = title(r'$R^{e_1}%s:=\widehat{R^{e_2}%s}|_W$'%(output_subscript, input_subscript), fontsize=fontsize)
t6 = title(r'$\mathcal{P}%s:=\widehat{\mathcal{P}%s}|_W$'%(output_subscript, input_subscript), fontsize=fontsize)
graphics_array([T1.plot()+bb+t1, T2.plot()+bb+t2, P.plot()+bb+t3,
inducedT1.plot()+bb+t4,
inducedT2.plot()+bb+t5,
inducedP.plot()+bb+t6], ncols=3).show(figsize=figsize)
show(LatexExpr(r"\text{The substitution is }"+
r"\beta{}:{}".format(input_subscript, latex(beta))))
y_ineq = [phi^-1, 0, -1] ### <= phi^-1 (see Polyhedron? for syntax)
R1e1,_ = R0e1.induced_transformation(y_ineq)
R1e2,_ = R0e2.induced_transformation(y_ineq)
P1,beta0 = R0e2.induced_partition(y_ineq, P0, substitution_type='column')
please_draw_Rauzy_induction_for_Z2_action(R0e1, R0e2, PU, R1e1, R1e2, P1, beta0, subscripts=[r'_0','_1'], figsize=8)
x_ineq = [phi^-1, -1, 0] ### x <= phi^-1 (see Polyhedron? for syntax)
R2e1,_ = R1e1.induced_transformation(x_ineq)
R2e2,_ = R1e2.induced_transformation(x_ineq)
P2,beta1 = R1e1.induced_partition(x_ineq, P1, substitution_type='row')
please_draw_Rauzy_induction_for_Z2_action(R1e1, R1e2, P1, R2e1, R2e2, P2, beta1, subscripts=[r'_1','_2'], figsize=8)
R2e1_scaled = (-phi*R2e1).translate_domain((1,1))
R2e2_scaled = (-phi*R2e2).translate_domain((1,1))
P2_scaled = (-phi*P2).translate((1,1))
t1 = title(r"$R^{e_1}_{2}$", fontsize=15);t2 = title(r"$R^{e_2}_{2}$", fontsize=15);t3 = title(r"$\mathcal{P}_{2}$", fontsize=15)
t4 = title(r"$R^{e_1}_{2'}$", fontsize=15);t5 = title(r"$R^{e_2}_{2'}$", fontsize=15);t6 = title(r"$\mathcal{P}_{2'}$", fontsize=15)
graphics_array([R2e1.plot()+bb+t1, R2e2.plot()+bb+t2, P2.plot()+bb+t3,
R2e1_scaled.plot()+t4, R2e2_scaled.plot()+t5, P2_scaled.plot()+t6], ncols=3).show(figsize=9)
We observe that the scaled partition $\Pcal_{2'}$ is the same as $\Pcal_0$ up to a permutation $\beta_2$ of the indices of the atoms in such a way that $\Xcal_{\Pcal_{2'},R_{2'}}=\beta_2\left(\Xcal_{\Pcal_0,R_0}\right)$
t1 = title(r'$\mathcal{P}_0$', fontsize=20);t2 = title(r'$\mathcal{P}_1$', fontsize=20)
t3 = title(r'$\mathcal{P}_2$', fontsize=20);t4 = title(r"$\mathcal{P}_{2'}$", fontsize=20)
L = [PU.plot()+t1, P1.plot()+bb+t2, P2.plot()+bb+t3, P2_scaled.plot()+t4, PU.plot()+t1]
graphics_array(L).show(figsize=15)
assert P2_scaled.is_equal_up_to_relabeling(PU)
from slabbe import Substitution2d
beta2 = Substitution2d.from_permutation(PU.keys_permutation(P2_scaled))
show(beta2)
In summary, we have
$$\begin{align*} \Xcal_{\Pcal_0,R_0} &= \overline{\beta_0(\Xcal_{\Pcal_1,R_1})}^\sigma = \overline{\beta_0\beta_1(\Xcal_{\Pcal_2,R_2})}^\sigma = \overline{\beta_0\beta_1(\Xcal_{\Pcal_{2'},R_{2'}})}^\sigma = \overline{\beta_0\beta_1\beta_2\left(\Xcal_{\Pcal_0,R_0}\right)}^\sigma \end{align*}$$with self-similarity $\phi=\beta_0\beta_1\beta_2$:
phi_ = beta0 * beta1 * beta2
show(phi_)
Moreover, one can prove (from the study of $2\times 2$ factors) that there is a unique subshift $X$ such that $X=\overline{\phi(X)}^\sigma$. Thus $$\Xcal_{\Pcal_0,R_0}=\Xcal_\phi.$$ Also $\phi$ is onto up to a shift and recognizable. Thus $\Xcal_\phi$ is aperiodic.
Another characterization of $\Xcal_{\Pcal_0,R_0}$ is the Wang shift $\Omega_\Ucal\subseteq[0,18]^{\mathbb{Z}^2}$ defined by a set $\Ucal$ of 19 Wang tiles.
from slabbe import WangTileSet
tiles = ["FOJO", "FOHL", "JMFP", "DMFK", "HPJP", "HPHN", "HKFP", "HKDP",
"BOIO", "GLEO", "GLCL", "ALIO", "EPGP", "EPIP", "IPGK", "IPIK",
"IKBM", "IKAK", "CNIP"]
U = WangTileSet([tuple(tile) for tile in tiles])
U.tikz()
which satisfies: $$\Omega_\Ucal =\overline{\alpha_0(\Omega_\Vcal)}^\sigma =\overline{\alpha_0\alpha_1(\Omega_\Wcal)}^\sigma =\overline{\alpha_0\alpha_1\alpha_2(\Omega_\Ucal)}^\sigma =\overline{\phi(\Omega_\Ucal)}^\sigma$$ and $$\beta_0=\alpha_0,\quad\beta_1=\alpha_1,\quad\quad\beta_2=\alpha_2.$$
The computation of $\alpha_0$, $\alpha_1$ and $\alpha_2$ is done using subset of marker tiles, see this other 30 minutes talk (online SDA2 meeting, Caen, December 2020) or this chapter arXiv:2012.03892
Theorem
Theorem There exists a 4-to-2 cut and project scheme such that for every configuration $w\in\Omega_\Ucal$, the set $Q\subseteq\Z^2$ of occurrences of a pattern in $w$ is a regular model set. If $w$ is a generic (resp. singular) configuration, then $Q$ is a generic (resp. singular) model set.
from slabbe import TikzPicture
with open('figure4.tex','r') as f:
s = f.read()
TikzPicture(s)
Installation:
sage -pip install slabbe
In case of trouble: email me.