This file contains the Sage code contained in the preprints:
- arXiv:1906.01104v1, June 2019, 36 p.
- arXiv:1906.01104v2, May 2020, 40 p.
- arXiv:1906.01104v3, January 2021, 40 p.
The Jupyter notebook arXiv_1906_01104.ipynb
is created from arXiv_1906_01104.rst
with the command sage -rst2ipynb arXiv_1906_01104.rst arXiv_1906_01104.ipynb
. The file arXiv_1906_01104.rst
is in the slabbe/demos
directory of the optional SageMath package slabbe.
Running all examples below with sage -t arXiv_1906_01104.rst
takes 10 seconds with sage-9.1 and slabbe-0.6.1 (or with sage-9.2 and slabbe-0.6.2).
%display latex # not tested
First we construct the golden mean as a element of a quadratic number field because it is more efficient for arithmetic operations and comparisons:
z = polygen(QQ, 'z')
K = NumberField(z**2-z-1, 'phi', embedding=RR(1.6))
phi = K.gen()
We import the polygon partition $\mathcal{P}_0$ of $\mathbb{R}^2/\Gamma_0$ : which is predefined in slabbe
:
from slabbe.arXiv_1903_06137 import jeandel_rao_wang_shift_partition
P0 = jeandel_rao_wang_shift_partition()
P0
P0.plot() # optional long
We import polyhedron exchange transformations from the package:
from slabbe import PolyhedronExchangeTransformation as PET
We define the lattice $\Gamma_0$ and the maps $R_0^{e_1}$, $R_0^{e_2}$ which can be seen as a polygon exchange transformations on a rectangular fundamental domain of $\mathbb{R}^2/\Gamma_0$ :
Gamma0 = matrix.column([(phi,0), (1,phi+3)])
fundamental_domain = polytopes.parallelotope([(phi,0), (0,phi+3)])
R0e1 = PET.toral_translation(Gamma0, vector((1,0)), fundamental_domain)
R0e2 = PET.toral_translation(Gamma0, vector((0,1)), fundamental_domain)
The following allows to compute the induced partition $\mathcal{P}_1$ of $\mathbb{R}^2/\Gamma_1$, the substitution $\beta_0$ and the $\mathbb{Z}^2$-action $R_1$ on $\mathbb{R}^2/\Gamma_1$.
y_le_1 = [1, 0, -1] # syntax for the inequality y <= 1
P1,beta0 = R0e2.induced_partition(y_le_1, P0, substitution_type='column')
R1e1,_ = R0e1.induced_transformation(y_le_1)
R1e2,_ = R0e2.induced_transformation(y_le_1)
R1e1
R1e1.plot() # optional long
R1e2
R1e2.plot() # optional long
P1
P1.plot() # optional long
beta0
We keep $\mathcal{P}_2$, $\Gamma_2$ equal to $\mathcal{P}_1$, $\Gamma_1$ and we change the base of the action to get the $\mathbb{Z}^2$-action $R_2$ on $\mathbb{R}^2/\Gamma_2$.
Gamma2 = Gamma1 = matrix.column([(phi,0), (0,1)])
P2 = P1
R2e1 = R1e1
R2e2 = (R1e1 * R1e2).merge_atoms_with_same_translation()
The following confirms that the $R_2^{\boldsymbol{e}_2}$ is now a vertical rotation on the torus $\mathbb{R^2}/\Gamma_2$.
R2e2
R2e2.plot() # optional long
The following allows to compute the induced partition $\mathcal{P}_3$ of $\mathbb{R}^2/\Gamma_3$, the substitution $\beta_2$ and the $\mathbb{Z}^2$-action $R_3$ on $\mathbb{R}^2/\Gamma_3$.
x_le_1 = [1, -1, 0] # syntax for x <= 1
P3,beta2 = R2e1.induced_partition(x_le_1, P2, substitution_type='row')
R3e1,_ = R2e1.induced_transformation(x_le_1)
R3e2,_ = R2e2.induced_transformation(x_le_1)
R3e1
P3
P3.plot() # optional long
beta2
The following allows to compute the induced partition $\mathcal{P}_4$ of $\mathbb{R}^2/\Gamma_4$, the substitution $\beta_3$ and the $\mathbb{Z}^2$-action $R_4$ on $\mathbb{R}^2/\Gamma_4$
x_le_phi_inv = [phi^-1, -1, 0] # syntax for x <= phi^-1
P4,beta3 = R3e1.induced_partition(x_le_phi_inv, P3, substitution_type='row')
R4e1,_ = R3e1.induced_transformation(x_le_phi_inv)
R4e2,_ = R3e2.induced_transformation(x_le_phi_inv)
R4e2
P4
P4.plot() # optional long
beta3
The following allows to compute the induced partition $\mathcal{P}_5$ of $\mathbb{R}^2/\Gamma_5$, the substitution $\beta_4$ and the $\mathbb{Z}^2$-action $R_5$ on $\mathbb{R}^2/\Gamma_5$.
y_le_phi_inv = [phi^-1, 0, -1] # syntax for y <= phi^-1
P5,beta4 = R4e2.induced_partition(y_le_phi_inv, P4, substitution_type='column')
R5e1,_ = R4e1.induced_transformation(y_le_phi_inv)
R5e2,_ = R4e2.induced_transformation(y_le_phi_inv)
P5
P5.plot() # optional long
beta4
We rescale the partition $\mathcal{P}_5$ :
P5_scaled = (-phi*P5).translate((1,1))
R5e1_scaled = (-phi*R5e1).translate_domain((1,1))
R5e2_scaled = (-phi*R5e2).translate_domain((1,1))
P5_scaled.plot() # optional long
The following allows to compute the induced partition $\mathcal{P}_6$ of $\mathbb{R}^2/\Gamma_6$, the substitution $\beta_5$ and the $\mathbb{Z}^2$-action $R_6$ on $\mathbb{R}^2/\Gamma_6$.
P6,beta5 = R5e1_scaled.induced_partition(x_le_phi_inv, P5_scaled, substitution_type='row')
R6e1,_ = R5e1_scaled.induced_transformation(x_le_phi_inv)
R6e2,_ = R5e2_scaled.induced_transformation(x_le_phi_inv)
P6
P6.plot() # optional long
beta5
The following allows to compute the induced partition $\mathcal{P}_7$ of $\mathbb{R}^2/\Gamma_7$, the substitution $\beta_6$ and the $\mathbb{Z}^2$-action $R_7$ on $\mathbb{R}^2/\Gamma_7$.
P7,beta6 = R6e2.induced_partition(y_le_phi_inv, P6, substitution_type='column')
R7e1,_ = R6e1.induced_transformation(y_le_phi_inv)
R7e2,_ = R6e2.induced_transformation(y_le_phi_inv)
P7
P7.plot() # optional long
beta6
We rescale the partition $\mathcal{P}_7$ :
P7_scaled = (-phi*P7).translate((1,1))
R7e1_scaled = (-phi*R7e1).translate_domain((1,1))
R7e2_scaled = (-phi*R7e2).translate_domain((1,1))
P7_scaled.plot() # optional long
The following allows to compute the induced partition $\mathcal{P}_8$ of $\mathbb{R}^2/\Gamma_8$, the substitution $\beta_7$ and the $\mathbb{Z}^2$-action $R_8$ on $\mathbb{R}^2/\Gamma_8$.
P8,beta7 = R7e1_scaled.induced_partition(x_le_phi_inv, P7_scaled, substitution_type='row')
R8e1,_ = R7e1_scaled.induced_transformation(x_le_phi_inv)
R8e2,_ = R7e2_scaled.induced_transformation(x_le_phi_inv)
P8
P8.plot() # optional long
beta7
The following allows to compute the induced partition $\mathcal{P}_9$ of $\mathbb{R}^2/\Gamma_9$, the substitution $\beta_8$ and the $\mathbb{Z}^2$-action $R_9$ on $\mathbb{R}^2/\Gamma_9$.
P9,beta8 = R8e2.induced_partition(y_le_phi_inv, P8, substitution_type='column')
R9e1,_ = R8e1.induced_transformation(y_le_phi_inv)
R9e2,_ = R8e2.induced_transformation(y_le_phi_inv)
P9
P9.plot() # optional long
beta8
We rescale the partition $\mathcal{P}_9$ :
P9_scaled = (-phi*P9).translate((1,1))
R9e1_scaled = (-phi*R9e1).translate_domain((1,1))
R9e2_scaled = (-phi*R9e2).translate_domain((1,1))
P9_scaled.plot() # optional long
The following allows to compute the induced partition $\mathcal{P}_{10}$ of $\mathbb{R}^2/\Gamma_{10}$, the substitution $\beta_9$ and the $\mathbb{Z}^2$-action $R_{10}$ on $\mathbb{R}^2/\Gamma_{10}$.
P10,beta9 = R9e1_scaled.induced_partition(x_le_phi_inv, P9_scaled, substitution_type='row')
R10e1,_ = R9e1_scaled.induced_transformation(x_le_phi_inv)
R10e2,_ = R9e2_scaled.induced_transformation(x_le_phi_inv)
P10
P10.plot() # optional long
beta9
We show that $\mathcal{P}_8$ and $\mathcal{P}_{10}$ are equivalent:
P8.is_equal_up_to_relabeling(P10)
from slabbe import Substitution2d
tau = Substitution2d.from_permutation(P8.keys_permutation(P10))
tau
beta8*beta9*tau # the self-similarity for P8
We may check that the self-similarity for $\mathcal{P}_8$ satisfies $\zeta^{-1}\beta_8\beta_9\tau\zeta=\beta_{\mathcal{U}}$.
zeta = Substitution2d.from_permutation({0:0, 1:1, 2:9, 3:7, 4:8, 5:11, 6:10,
7:6, 8:2, 9:4, 10:5, 11:3, 12:18, 13:14, 14:16, 15:13, 16:12, 17:17, 18:15})
betaU = Substitution2d({0: [[17]], 1: [[16]], 2: [[15], [11]], 3: [[13], [9]], 4: [[17], [8]], 5: [[16], [8]], 6: [[15], [8]], 7: [[14], [8]], 8: [[14, 6]], 9: [[17, 3]], 10: [[16, 3]], 11: [[14, 2]], 12: [[15, 7], [11, 1]], 13: [[14, 6], [11, 1]], 14: [[13, 7], [9, 1]], 15: [[12, 6], [9, 1]], 16: [[18, 5], [10, 1]], 17: [[13, 4], [9, 1]], 18: [[14, 2], [8, 0]]})
zeta.inverse()*beta8*beta9*tau*zeta == betaU
betaU
Observe that the $19 \times 19$ incidence matrix of $\beta_8\beta_9\tau$ is not hyperbolic but, as shown by its characteristic polynomial, it is hyperbolic on a 8-dimensional subspace:
(beta8*beta9*tau).incidence_matrix().charpoly().factor()