$$\def\CC{\bf C} \def\QQ{\bf Q} \def\RR{\bf R} \def\ZZ{\bf Z} \def\NN{\bf N}$$

# Rauzy induction of polygon partitions and toral $\mathbb{Z}^2$-rotations¶

This file contains the Sage code contained in the preprints:

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).

In [1]:
%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:

In [2]:
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 :

In [3]:
from slabbe.arXiv_1903_06137 import jeandel_rao_wang_shift_partition
P0 = jeandel_rao_wang_shift_partition()
P0

Out[3]:
In [4]:
P0.plot()                    # optional long

Out[4]:

We import polyhedron exchange transformations from the package:

In [5]:
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$ :

In [6]:
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$.

In [7]:
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)

In [8]:
R1e1

Out[8]:
In [9]:
R1e1.plot()              # optional long

Out[9]:
In [10]:
R1e2

Out[10]:
In [11]:
R1e2.plot()              # optional long

Out[11]:
In [12]:
P1

Out[12]:
In [13]:
P1.plot()                    # optional long

Out[13]:
In [14]:
beta0

Out[14]:

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$.

In [15]:
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$.

In [16]:
R2e2

Out[16]:
In [17]:
R2e2.plot()              # optional long

Out[17]:

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$.

In [18]:
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

Out[18]:
In [19]:
P3

Out[19]:
In [20]:
P3.plot()                    # optional long

Out[20]:
In [21]:
beta2

Out[21]:

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$

In [22]:
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

Out[22]:
In [23]:
P4

Out[23]:
In [24]:
P4.plot()                    # optional long

Out[24]:
In [25]:
beta3

Out[25]:

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$.

In [26]:
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

Out[26]:
In [27]:
P5.plot()                    # optional long

Out[27]:
In [28]:
beta4

Out[28]:

We rescale the partition $\mathcal{P}_5$ :

In [29]:
P5_scaled = (-phi*P5).translate((1,1))
R5e1_scaled = (-phi*R5e1).translate_domain((1,1))
R5e2_scaled = (-phi*R5e2).translate_domain((1,1))

In [30]:
P5_scaled.plot()                  # optional long

Out[30]:

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$.

In [31]:
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

Out[31]:
In [32]:
P6.plot()                    # optional long

Out[32]:
In [33]:
beta5

Out[33]:

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$.

In [34]:
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

Out[34]:
In [35]:
P7.plot()                    # optional long

Out[35]:
In [36]:
beta6

Out[36]:

We rescale the partition $\mathcal{P}_7$ :

In [37]:
P7_scaled = (-phi*P7).translate((1,1))
R7e1_scaled = (-phi*R7e1).translate_domain((1,1))
R7e2_scaled = (-phi*R7e2).translate_domain((1,1))

In [38]:
P7_scaled.plot()                  # optional long

Out[38]:

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$.

In [39]:
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

Out[39]:
In [40]:
P8.plot()                    # optional long

Out[40]:
In [41]:
beta7

Out[41]:

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$.

In [42]:
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

Out[42]:
In [43]:
P9.plot()                    # optional long

Out[43]:
In [44]:
beta8

Out[44]:

We rescale the partition $\mathcal{P}_9$ :

In [45]:
P9_scaled = (-phi*P9).translate((1,1))
R9e1_scaled = (-phi*R9e1).translate_domain((1,1))
R9e2_scaled = (-phi*R9e2).translate_domain((1,1))

In [46]:
P9_scaled.plot()                  # optional long

Out[46]:

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}$.

In [47]:
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

Out[47]:
In [48]:
P10.plot()                    # optional long

Out[48]:
In [49]:
beta9

Out[49]:

We show that $\mathcal{P}_8$ and $\mathcal{P}_{10}$ are equivalent:

In [50]:
P8.is_equal_up_to_relabeling(P10)

Out[50]:
In [51]:
from slabbe import Substitution2d
tau = Substitution2d.from_permutation(P8.keys_permutation(P10))
tau

Out[51]:
In [52]:
beta8*beta9*tau    # the self-similarity for P8

Out[52]:

We may check that the self-similarity for $\mathcal{P}_8$ satisfies $\zeta^{-1}\beta_8\beta_9\tau\zeta=\beta_{\mathcal{U}}$.

In [53]:
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

Out[53]:
In [54]:
betaU

Out[54]:

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:

In [55]:
(beta8*beta9*tau).incidence_matrix().charpoly().factor()

Out[55]: