Cut and Project Scheme

Cut and project schemes and model sets

Based on the definitions presented in the book [BG13].

AUTHORS:

  • Sébastien Labbé, initial version + first plot method, February 2023 (Sage Days 117, Le Teich)

  • Carole Porrier and Sébastien Labbé, creation of cut-and-project from slopes, Golden-Octagonal, Ammann-Beenker, subperiods, February 2025 (Sage Days 128, Le Teich)

REFERENCES:

[BG13]

Baake, Michael, Uwe Grimm. Aperiodic order. Vol. 1. Vol. 149. Encyclopedia of Mathematics and its Applications. Cambridge University Press, Cambridge, 2013.

class slabbe.cut_and_project_scheme.CutAndProjectScheme(base_ring, pi, pi_int, lattice=None, check=True)

Bases: SageObject

INPUT:

  • base_ring – ring

  • pi\(n\times d\) matrix, projection of the ambiant space to

    the physical space

  • pi_int\(n\times (n-d)\) matrix, projection of the ambiant space

    to the internal space

  • lattice\(n\times n\) matrix (default:None), the columns form a base of a lattice in R^n, if None, it uses the \(n\times n\) identity matrix

  • check – boolean (default:True), whether to check that

    dimensions of the matrices given as input are consistent

EXAMPLES:

sage: from slabbe import CutAndProjectScheme
sage: z = polygen(QQ, 'z')
sage: K = NumberField(z**2-z-1, 'phi', embedding=RR(1.6))
sage: phi = K.gen()
sage: pi = matrix([[phi, 1]])
sage: pi_int = matrix([[-~phi, 1]])
sage: lattice = identity_matrix(2)
sage: cap = CutAndProjectScheme(K, pi, pi_int, lattice)
ambiant_space()

Return the ambiant space

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.ambiant_space()
Ambient free module of rank 2 over the principal ideal domain
Integer Ring
ambiant_space_dimension()

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.ambiant_space_dimension()
2
base_ring()

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.base_ring()
Number Field in phi with defining polynomial z^2 - z - 1 with phi = 1.618033988749895?
canonical_model_set(intervals='zero_one', shift=None)

Return the canoncial model set using a hypercube as window after projection in the internal space.

INPUT:

  • intervals – (default: 'zero_one') intervals defining the hypercube

  • shift\(n\)-dimensional vector translating the internal window to avoid singular tilings and Conway worms, where \(n\) is the dimension of the ambiant space

EXAMPLES:

sage: from slabbe import CutAndProjectScheme
sage: E = matrix([[1,1,1,1], [1,2,3,4]])
sage: c = CutAndProjectScheme.from_slope(E)
sage: m = c.canonical_model_set()
sage: m
Model Set of a 4-to-2 cut and project scheme

Golden-Octagonal:

sage: z = polygen(QQ, 'z')
sage: K = NumberField(z**2-z-1, 'phi', embedding=RR(1.6))
sage: phi = K.gen()
sage: E = matrix([[-1,0,phi,phi], [0,1,phi,1]])
sage: c = CutAndProjectScheme.from_slope(E)
sage: m = c.canonical_model_set()
sage: m
Model Set of a 4-to-2 cut and project scheme

With shift:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: shift = vector((1,-1,2,-1,-1)) / 1000
sage: c.canonical_model_set(shift=shift)
Model Set of a 5-to-2 cut and project scheme

TESTS:

sage: c = cut_and_project_schemes.GoldenOctagonal(projection='roots_of_unity')
sage: m = c.canonical_model_set(shift=None)
change_physical_projection(pi)
classmethod from_slope(E, projection='gram_schmidt', verbose=False)

Compute the orthogonal projection on the internal space (orthogonal of the slope)

The slope refers to vector space in the ambiant space corresponding to kernel of the pi_int projection [FP24].

The construction of the projection in the internal space from the slope using Gramm-Schmidt is made acording to Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

INPUT:

  • E – matrix, whose rows span the slope

  • projection – string (default:'gram_schmidt'), possible values are 'gram_schmidt' and 'roots_of_unity' (works only for n->2 tilings)

  • verbose – bool (default:False)

OUTPUT:

A cut and project scheme whose kernel of the internal projection is the vector space E.

EXAMPLES:

sage: from slabbe import CutAndProjectScheme
sage: E = matrix([[1,1,1,1], [1,2,3,4]])
sage: E
[1 1 1 1]
[1 2 3 4]
sage: c = CutAndProjectScheme.from_slope(E)
sage: c
4-to-2 cut and project scheme
sage: print(c)
4-to-2 cut and project scheme over
Rational Field
Projection to physical space:
[   1    1    1    1]
[-3/2 -1/2  1/2  3/2]
Projection to internal space:
[   1    0   -3    2]
[-4/7    1 -2/7 -1/7]
Lattice generated by the columns of:
[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]
sage: E = matrix([[1,1,1,1], [1,2,3,4]])
sage: c = CutAndProjectScheme.from_slope(E, projection='roots_of_unity')

REFERENCES:

[FP24] (1,2)

Thomas Fernique, Carole Porrier, Ammann Bars for Octagonal Tilings, Discrete Mathematics & Theoretical Computer Science 26 (2024), https://doi.org/10.46298/dmtcs.10764

internal_space()

Return the internal space

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.internal_space()
Vector space of dimension 1 over Number Field in phi with
defining polynomial z^2 - z - 1 with phi = 1.618033988749895?
internal_space_dimension()

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.internal_space_dimension()
1
internal_space_projection()

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.internal_space_projection()
[-phi + 1        1]
is_determined_by_subperiods()

Return whether the slope of the cut-and-project scheme is determined by the subperiods.

A subperiod is a vector of n entries where \(d+1\) are integers [BF2015].

The computation made below comes from Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

OUTPUT:

todo

EXAMPLES:

The Penrose hull is determined by its subperiods:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: c.is_determined_by_subperiods()
True

Ammann-Beenker is not determined by its subperiods:

sage: c = cut_and_project_schemes.AmmannBeenker()
sage: c.is_determined_by_subperiods()
False

Jeandel-Rao seems not to be determined by its subperiods (?):

sage: c = cut_and_project_schemes.JeandelRao()
sage: c.is_determined_by_subperiods()
False
is_orthogonal()

Return whether the two projections are orthogonal.

TODO: Is this the good name for this method?

EXAMPLES:

sage: from slabbe import CutAndProjectScheme
sage: E = matrix([[1,1,1,1], [1,2,3,4]])
sage: c = CutAndProjectScheme.from_slope(E)
sage: c.is_orthogonal()
True
is_valid(projection=None, verbose=False)

Return True if the physical space projection is valid.

A projection is valid if the rhombi do not overlap after projection in the physical space, that is, tiles do not create accordions in the physical space [H2004].

The computation of the validity made below comes from Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

Note

The current code checks that the orientation of the projection of each pair of vectors is the same in the slope and after projection in the physical space.

INPUT:

  • projection – matrix (default:None), if None it uses the physical space projection

  • verobse – bool (default:False)

OUTPUT:

boolean

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: c.is_valid()
True

REFERENCE:

[H2004]

Edmund Harriss, On canonical substitution tilings, Ph. D. Thesis, Univeristy of London, 2004.

lattice()

Return the lattice

OUTPUT:

a matrix whose columns generate the lattice

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.lattice()
[1 0]
[0 1]
lattice_base()

Return the lattice base

OUTPUT:

a matrix whose columns generate the lattice

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.lattice_base()
[(1, 0), (0, 1)]
lattice_neighbors(v)

Return the neighbors of a point according to the base of the lattice

INPUT:

  • v – tuple or vector, in the ambiant space

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: v = vector((10, 10))
sage: cap.lattice_neighbors(v)
[(11, 10), (10, 11), (9, 10), (10, 9)]
orthogonal_physical_projection_cut_and_project_scheme()

EXAMPLES:

sage: # TODO
physical_space()

Return the physical space

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.physical_space()
Vector space of dimension 1 over Number Field in phi with
defining polynomial z^2 - z - 1 with phi = 1.618033988749895?
physical_space_dimension()

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.physical_space_dimension()
1
physical_space_projection()

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cap = cut_and_project_schemes.Fibonacci()
sage: cap.physical_space_projection()
[      1 phi - 1]
shadow_periods()

Return the periods of the shadows of the cut and project scheme.

A shadow period is the integer entries of a subperiod of the cut and project scheme [BF2015].

A subperiod is a vector of n entries where \(d+1\) are integers.

The computation of the shadow periods made below comes from Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

OUTPUT:

list of pairs (t,s) where t is a tuple of indices where the entries are integers equal to s

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: c.shadow_periods()
[((0, 1, 2), (1, 0, -1)),
 ((0, 1, 3), (1, -1, 0)),
 ((0, 1, 4), (0, 1, -1)),
 ((0, 2, 3), (0, 1, -1)),
 ((0, 2, 4), (1, 0, -1)),
 ((0, 3, 4), (1, -1, 0)),
 ((1, 2, 3), (1, 0, -1)),
 ((1, 2, 4), (1, -1, 0)),
 ((1, 3, 4), (0, 1, -1)),
 ((2, 3, 4), (1, 0, -1))]
sage: c = cut_and_project_schemes.JeandelRao()
sage: c.shadow_periods()
[((0, 1, 2), (1, 3, 5)),
 ((0, 1, 3), (0, 1, 1)),
 ((0, 2, 3), (1, 0, 0)),
 ((1, 2, 3), (1, 0, 0))]

REFERENCE:

[BF2015] (1,2,3)

Bédaride, Nicolas, et Thomas Fernique. « When Periodicities Enforce Aperiodicity ». Communications in Mathematical Physics 335, nᵒ 3 (1 mai 2015): 1099‑1120. https://doi.org/10.1007/s00220-015-2334-8.

slope()

Return the slope of the cut-and project scheme.

The slope refers to vector space in the ambiant space corresponding to kernel of the pi_int projection [FP24].

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: slope = c.slope(); slope
Vector space of degree 5 and dimension 2 over Number Field in a with defining polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?
Basis matrix:
[       1        0       -1  a^2 - 2 -a^2 + 2]
[       0        1 -a^2 + 2  a^2 - 2       -1]
sage: slope.matrix().n(digits=5)
[  1.0000  0.00000  -1.0000 -0.61803  0.61803]
[ 0.00000   1.0000  0.61803 -0.61803  -1.0000]
sage: c = cut_and_project_schemes.JeandelRao()
sage: c.slope()
Vector space of degree 4 and dimension 2 over Number Field in phi with defining polynomial z^2 - z - 1 with phi = 1.618033988749895?
Basis matrix:
[         1          0 -3*phi - 1       -phi]
[         0          1    phi + 2          1]
star_map()
subperiods()

Return the subperiods of the cut and project scheme.

A subperiod is a vector of n entries where \(d+1\) are integers [BF2015].

The computation of the subperiods made below comes from Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

OUTPUT:

todo

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: P = c.subperiods()            # long time (3s)
sage: P                             # long time
[(1, 0, -1, a^2 - 2, -a^2 + 2),
 (1, -1, a^2 - 3, 0, -a^2 + 3),
 (0, 1, -a^2 + 2, a^2 - 2, -1),
 (0, -a^2 + 3, 1, -1, a^2 - 3),
 (1, -a^2 + 3, 0, a^2 - 3, -1),
 (1, -a^2 + 2, a^2 - 2, -1, 0),
 (-a^2 + 2, 1, 0, -1, a^2 - 2),
 (-a^2 + 3, 1, -1, a^2 - 3, 0),
 (a^2 - 3, 0, -a^2 + 3, 1, -1),
 (a^2 - 2, -a^2 + 2, 1, 0, -1)]

The same in terms of the golden ratio:

sage: K.<phi> = NumberField(x**2-x-1, 'phi', embedding=RR(1.6))
sage: [p.change_ring(K) for p in P]    # long time
[(1, 0, -1, -phi + 1, phi - 1),
 (1, -1, -phi, 0, phi),
 (0, 1, phi - 1, -phi + 1, -1),
 (0, phi, 1, -1, -phi),
 (1, phi, 0, -phi, -1),
 (1, phi - 1, -phi + 1, -1, 0),
 (phi - 1, 1, 0, -1, -phi + 1),
 (phi, 1, -1, -phi, 0),
 (-phi, 0, phi, 1, -1),
 (-phi + 1, phi - 1, 1, 0, -1)]
class slabbe.cut_and_project_scheme.CutAndProjectSchemeGenerator

Bases: object

Constructor of several famous cut and project schemes

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.Fibonacci()
2-to-1 cut and project scheme
AmmannBeenker()

Return the Ammann-Beenker cut and project scheme

The choice of the matrix E whose rows generate the slope, that is, the kernel of the pi_int projection, is made acording to Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.AmmannBeenker()
4-to-2 cut and project scheme
sage: c = cut_and_project_schemes.AmmannBeenker()
sage: m = c.canonical_model_set(shift=vector((1,1,1,1))/100)
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: G = m.plot_in_physical_space(W)      # long time (1s)
sage: G.show(aspect_ratio=1, figsize=20)   # long time
Cyrenaic()

Return the Cyrenaic cut and proect scheme

The choice of the matrix E whose rows generate the slope, that is, the kernel of the pi_int projection, is made acording to Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.Cyrenaic()
4-to-2 cut and project scheme
sage: c = cut_and_project_schemes.Cyrenaic()
sage: m = c.canonical_model_set(shift=vector((1,1,1,1))/100)
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: G = m.plot_in_physical_space(W)      # long time (1s)
sage: G.show(aspect_ratio=1, figsize=20)   # long time
Fibonacci()

Return the Fibonacci cut and project scheme

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.Fibonacci()
2-to-1 cut and project scheme
Fibonacci2D()

Return the 2D Fibonacci cut and project scheme

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.Fibonacci2D()
4-to-2 cut and project scheme
Fibonacci_the_Minkowski_way()

Return the Fibonacci cut and project scheme

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.Fibonacci_the_Minkowski_way()
2-to-1 cut and project scheme
sage: print(cut_and_project_schemes.Fibonacci_the_Minkowski_way())
2-to-1 cut and project scheme over
Number Field in phi with defining polynomial z^2 - z - 1 with
phi = 1.618033988749895?
Projection to physical space:
[1 0]
Projection to internal space:
[0 1]
Lattice generated by the columns of:
[       1      phi]
[       1 -phi + 1]
GoldenOctagonal(projection='gram_schmidt')

Return the Golden-Octagonal cut and project scheme

The choice of the matrix E whose rows generate the slope, that is, the kernel of the pi_int projection, is made acording to Carole Porrier’s code available at https://github.com/cporrier/Cyrenaic

INPUT:

  • projection – string (default:'gram_schmidt'), possible values are 'gram_schmidt' and 'roots_of_unity'

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.GoldenOctagonal()
4-to-2 cut and project scheme
JeandelRao(algorithm=0)

Return the Jeandel-Rao cut and proect scheme as given in [L21].

INPUT:

  • algorithm – integer

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.JeandelRao()
sage: c
4-to-2 cut and project scheme
sage: print(c)
4-to-2 cut and project scheme over
Number Field in phi with defining polynomial z^2 - z - 1 with
phi = 1.618033988749895?
Projection to physical space:
[1 1 0 0]
[0 0 1 1]
Projection to internal space:
[       1 -phi + 1        0  phi - 1]
[       0        0        1 -phi - 2]
Lattice generated by the columns of:
[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]

The third version has valid projection in the physical space:

sage: c = cut_and_project_schemes.JeandelRao()
sage: c.is_valid(verbose=True)
projection minors sign =  [0, 1, 1, 1, 1, 0]
slope minors sign      =  [1, 1, 1, 1, 1, 0]
False
sage: c = cut_and_project_schemes.JeandelRao(3)
sage: c.is_valid(verbose=True)
projection minors sign =  [1, 1, 1, 1, 1, 0]
slope minors sign      =  [1, 1, 1, 1, 1, 0]
True

REFERENCES:

[L21] (1,2)

Labbé, Sébastien. Markov Partitions for Toral $mathbb{Z}^2$-Rotations Featuring Jeandel–Rao Wang Shift and Model Sets, Annales Henri Lebesgue 4 (2021) 283‑324. https://doi.org/10.5802/ahl.73.

Penrose(algorithm='degree4')

Return the Penrose cut and project scheme

INPUT:

  • algorithm – string (default:'degree4'), valid options are:

    • 'degree4' – computations are made in the number field of degree 4

    • 'Carole_gram_schmidt' – physical projection is not orthonormal

    • 'Carole_roots_of_unity' – computations are made in the Algebraic field (computations are slower)

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.Penrose()
5-to-2 cut and project scheme
sage: c = cut_and_project_schemes.Penrose(algorithm='Carole_gram_schmidt')
sage: c
5-to-2 cut and project scheme
self_similar_19_tiles()

Return the self-similar 19 Wang tiles cut and project scheme from [L21].

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: cut_and_project_schemes.self_similar_19_tiles()
4-to-2 cut and project scheme
class slabbe.cut_and_project_scheme.ModelSet(cut_and_project_scheme, window)

Bases: SageObject

Regular Euclidean model set

INPUT:

  • cut_and_project_schemes – a cut and project scheme

  • window – polyhedron

EXAMPLES:

sage: from slabbe import cut_and_project_schemes, ModelSet
sage: cap = cut_and_project_schemes.Fibonacci()
sage: phi = cap.base_ring().gen()
sage: W = Polyhedron([(-1,),(phi-1,)])
sage: m = ModelSet(cap, W)
ambiant_compact_strip(physical_window)

Return the preimage of the window in the internal space by the projection in the internal space.

INPUT:

  • physical_window – polyhedron

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: m.ambiant_compact_strip(W)
A 2-dimensional polyhedron in (Number Field in phi with
defining polynomial z^2 - z - 1 with phi =
1.618033988749895?)^2 defined as the convex hull of 4 vertices

Penrose tiling:

sage: m = model_sets.Penrose()
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: m.ambiant_compact_strip(W)
A 5-dimensional polyhedron in (Number Field in a with
defining polynomial z^4 - 5*z^2 + 5 with a =
1.175570504584947?)^5 defined as the convex hull of 88
vertices

We move the window to force a resolution of the Conway worms:

sage: shift = vector((1,-1,2,-1,-1)) / 1000
sage: m = model_sets.Penrose(shift)
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: m.ambiant_compact_strip(W)
A 5-dimensional polyhedron in (Number Field in a with defining
polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?)^5
defined as the convex hull of 88 vertices
coding_region(P)

Return the region in the window associated with a subset of points of the lattice.

INPUT:

  • P– list, subset of vertices of the lattice

OUTPUT:

a polytope

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.Penrose()
sage: m = c.canonical_model_set(shift=vector((1,1,1,1,1))/100)
sage: P = [(0,0,0,0,0), (0,1,0,0,0), (0,0,1,0,0), (0,0,0,1,0)]
sage: m.coding_region(P)
A 3-dimensional polyhedron in (Number Field in a with defining
polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?)^3 defined
as the convex hull of 11 vertices

The region may be empty:

sage: P = [(0,0,0,0,0),(0,1,0,0,0),(0,0,1,0,0),(0,0,0,10,0)]
sage: m.coding_region(P)
The empty polyhedron in (Number Field in a with defining
polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?)^3
cut(physical_window)

Return the lattice points that are projected in the internal space window (and that are projected to the provided physical space window).

INPUT:

  • physical_window – polyhedron

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: m.cut(W)
[(3, 2), (4, 2), (3, 1), (4, 3), (2, 1), (5, 3), (1, 1), (6,
3), (1, 0), (6, 4), (0, 0), (7, 4)]
cut_and_project(physical_window)

Return the model set restricted to a window in the physical space

INPUT:

  • physical_window – polyhedron

OUTPUT:

list

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: sorted(m.cut_and_project(W))
[(0),
 (1),
 (phi),
 (phi + 1),
 (phi + 2),
 (2*phi + 1),
 (2*phi + 2),
 (3*phi + 1),
 (3*phi + 2),
 (3*phi + 3),
 (4*phi + 2),
 (4*phi + 3)]
cut_and_project_scheme()
cut_edges(physical_window)

Return the edges linking lattice points that are projected in the internal space window (and that are projected to the provided physical space window).

INPUT:

  • physical_window – polyhedron

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: sorted(sorted(edge) for edge in m.cut_edges(W))
[[(0, 0), (1, 0)],
 [(1, 0), (1, 1)],
 [(1, 1), (2, 1)],
 [(2, 1), (3, 1)],
 [(3, 1), (3, 2)],
 [(3, 2), (4, 2)],
 [(4, 2), (4, 3)],
 [(4, 3), (5, 3)],
 [(5, 3), (6, 3)],
 [(6, 3), (6, 4)],
 [(6, 4), (7, 4)]]
internal_space_window_preimage()

Return the preimage of the window in the internal space by the projection in the internal space.

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: m.internal_space_window_preimage()
A 2-dimensional polyhedron in (Number Field in phi with defining polynomial z^2 - z - 1
with phi = 1.618033988749895?)^2 defined as the convex hull of 2 vertices and 1 line

Penrose tiling:

sage: m = model_sets.Penrose()
sage: strip = m.internal_space_window_preimage()
sage: strip
A 5-dimensional polyhedron in (Number Field in a with defining
polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?)^5
defined as the convex hull of 22 vertices and 2 lines
sage: vector((0,0,0,0,0)) in strip
True

We move the window to force a resolution of the Conway worms:

sage: shift = vector((1,-1,2,-1,-1)) / 1000
sage: m = model_sets.Penrose(shift)
sage: strip = m.internal_space_window_preimage()
sage: vector((0,0,0,0,0)) in strip
False
sage: vector((1,1,1,1,1)) in strip
False

TESTS:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.GoldenOctagonal(projection='roots_of_unity')
sage: m = c.canonical_model_set(shift=vector((1,1,1,1))/100)
sage: m.internal_space_window_preimage()
A 4-dimensional polyhedron in (Number Field in phi with
defining polynomial z^2 - z - 1 with phi =
1.618033988749895?)^4 defined as the convex hull of 8 vertices
and 2 lines
is_Meyer()
is_generic()
is_regular()
is_relatively_dense()
is_singular()
is_uniformly_discrete()
lattice_neighbors_projected_in_window(v)

Return the neighbors of a point that are projected in the (internal space) window

INPUT:

  • v – tuple or vector, in the ambiant space

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: v = vector((0,0))
sage: m.lattice_neighbors_projected_in_window(v)
[(1, 0), (-1, 0), (0, -1)]
physical_space_window_preimage(physical_window)

Return the preimage of the window in the internal space by the projection in the internal space.

INPUT:

  • physical_window – polyhedron

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: m.physical_space_window_preimage(W)
A 2-dimensional polyhedron in (Number Field in phi with defining polynomial z^2 - z - 1
with phi = 1.618033988749895?)^2 defined as the convex hull of 2 vertices and 1 line

Penrose tiling:

sage: m = model_sets.Penrose()
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: strip = m.physical_space_window_preimage(W)
sage: strip
A 5-dimensional polyhedron in (Number Field in a with defining
polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?)^5
defined as the convex hull of 4 vertices and 3 lines

We move the window to force a resolution of the Conway worms:

sage: shift = vector((1,-1,2,-1,-1)) / 1000
sage: m = model_sets.Penrose(shift)
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: strip = m.physical_space_window_preimage(W)
sage: strip
A 5-dimensional polyhedron in (Number Field in a with defining
polynomial z^4 - 5*z^2 + 5 with a = 1.175570504584947?)^5
defined as the convex hull of 4 vertices and 3 lines
plot_in_ambiant_space(physical_window, pointsize=100)

Return a Graphics representing the model set restricted to a window in the physical space (seen in the ambiant space)

INPUT:

  • physical_window – polyhedron

  • pointsize – integer (default:20)

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(-10,),(10,)])
sage: G = m.plot_in_ambiant_space(W)        # long time (1s)
sage: G.show(aspect_ratio=1, figsize=20)    # long time

TODO: The following needs a little fix since the slope is zero (some limit case for the region_plot):

sage: m = model_sets.Fibonacci_the_Minkowski_way()
sage: W = Polyhedron([(-10,),(10,)])
sage: G = m.plot_in_ambiant_space(W)        # long time (1s)
sage: G.show(aspect_ratio=1, figsize=20)    # known bug

TESTS:

sage: m = model_sets.Fibonacci2D()
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: G = m.plot_in_ambiant_space(W)
Traceback (most recent call last):
...
NotImplementedError: when physical space dimension is 2 and
ambiant space dimension is 4
plot_in_physical_space(physical_window, pointsize=20)

Return a Graphics representing the model set restricted to a window in the physical space

INPUT:

  • physical_window – polyhedron

  • pointsize – integer (default:20)

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci2D()
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: G = m.plot_in_physical_space(W)      # long time (1s)
sage: G.show(aspect_ratio=1, figsize=20)   # long time

Penrose tiling:

sage: m = model_sets.Penrose()
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: G = m.plot_in_physical_space(W)      # long time (5s)
sage: G.show(aspect_ratio=1, figsize=20)   # long time

We move the window to force a resolution of the Conway worms:

sage: shift = vector((1,-1,2,-1,-1)) / 1000
sage: m = model_sets.Penrose(shift)
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: G = m.plot_in_physical_space(W)      # long time (4s)
sage: G.show(aspect_ratio=1, figsize=20)   # long time

TODO, Bug!!:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.GoldenOctagonal(projection='roots_of_unity')
sage: m = c.canonical_model_set(shift=vector((1,1,1,1))/100)
sage: m.plot_in_physical_space(W).show(figsize=20)
Traceback (most recent call last):
...
ValueError: invalid base ring: Number Field in zeta80 with defining
polynomial x^2 - 2 with zeta80 = 1.414213562373095? cannot be coerced to a real
field

TESTS:

sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(-10,),(10,)])
sage: G = m.plot_in_physical_space(W)
Traceback (most recent call last):
...
NotImplementedError: when physical space dimension is 1
some_element_of_lattice_in_the_strip(physical_window)

Return the lattice points that are projected in the internal space window (and that are projected to the provided physical space window).

INPUT:

  • physical_window – polyhedron

OUTPUT:

vector

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: m.some_element_of_lattice_in_the_strip(W)
(3, 2)

Penrose tiling:

sage: m = model_sets.Penrose()
sage: W = polytopes.hypercube(2, intervals=[(-10,10), (-10,10)])
sage: m.some_element_of_lattice_in_the_strip(W)
(0, 0, 0, 0, 0)
successor_map(physical_window)

Return the successor map of points in the lattice projected in both windows.

INPUT:

  • physical_window – polyhedron

EXAMPLES:

sage: from slabbe import model_sets
sage: m = model_sets.Fibonacci()
sage: W = Polyhedron([(0,),(10,)])
sage: succ = m.successor_map(W)
sage: succ(vector((0,0)))
[(1, 0)]
window()
class slabbe.cut_and_project_scheme.ModelSetGenerator

Bases: object

Constructor of several famous model sets

EXAMPLES:

sage: from slabbe import model_sets
sage: model_sets.Fibonacci()
Model Set of a 2-to-1 cut and project scheme
Fibonacci()

Return the Fibonacci cut and project scheme

EXAMPLES:

sage: from slabbe import model_sets
sage: model_sets.Fibonacci()
Model Set of a 2-to-1 cut and project scheme
Fibonacci2D()

Return the 2D Fibonacci cut and project scheme

EXAMPLES:

sage: from slabbe import model_sets
sage: model_sets.Fibonacci2D()
Model Set of a 4-to-2 cut and project scheme
Fibonacci_the_Minkowski_way()

Return the Fibonacci cut and project scheme

EXAMPLES:

sage: from slabbe import model_sets
sage: model_sets.Fibonacci_the_Minkowski_way()
Model Set of a 2-to-1 cut and project scheme
GoldenOctagonal(shift=None)

Return the Golden-Octagonal cut and project scheme

INPUT:

  • shift – 4-dimensional vector translating the internal window to avoid singular tilings and Conway worms

EXAMPLES:

sage: from slabbe import model_sets
sage: model_sets.GoldenOctagonal()
Model Set of a 4-to-2 cut and project scheme
sage: shift = vector((1,-1,2,-1)) / 1000
sage: model_sets.GoldenOctagonal(shift)
Model Set of a 4-to-2 cut and project scheme
Penrose(shift=None)

Return the Penrose cut and project scheme

INPUT:

  • shift – 5-dimensional vector translating the internal window to avoid singular tilings and Conway worms

EXAMPLES:

sage: from slabbe import model_sets
sage: model_sets.Penrose()
Model Set of a 5-to-2 cut and project scheme
sage: shift = vector((1,-1,2,-1,-1)) / 1000
sage: model_sets.Penrose(shift)
Model Set of a 5-to-2 cut and project scheme
slabbe.cut_and_project_scheme.hypercube_pet(M, i)

EXAMPLES:

sage: from slabbe import cut_and_project_schemes
sage: c = cut_and_project_schemes.GoldenOctagonal(projection='roots_of_unity')
sage: M = c._pi_int.change_ring(RDF)
sage: M
[                1.0                 0.0                -1.0   1.618033988749895]
[-0.9172881767044976                 1.0 -0.7007458120453971 0.13383054136359823]
sage: from slabbe.cut_and_project_scheme import hypercube_pet
sage: T = hypercube_pet(M, 0)
sage: T
Polyhedron Exchange Transformation of
Polyhedron partition of 4 atoms with 4 letters
with translations {'123': (1.0, -0.9172881767044976), '01':
(-2.618033989, -0.8345763534), '03': (1.0000000000000002, 1.7007458117), '02':
(-1.618033989, 0.8661694583)}