Frieze Patterns

This implements the original frieze patterns due to Conway and Coxeter. Such a frieze pattern is considered as a sequence of nonnegative integers following [CoCo1] and [CoCo2] using sage.combinat.path_tableaux.path_tableau.

AUTHORS:

  • Bruce Westbury (2019): initial version

class sage.combinat.path_tableaux.frieze.FriezePattern[source]

Bases: PathTableau

A frieze pattern.

We encode a frieze pattern as a sequence in a fixed ground field.

INPUT:

  • fp – a sequence of elements of field

  • field – (default: QQ) the ground field

EXAMPLES:

sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1])
sage: path_tableaux.CylindricalDiagram(t)
[0, 1, 2, 1, 2, 3, 1, 0]
[ , 0, 1, 1, 3, 5, 2, 1, 0]
[ ,  , 0, 1, 4, 7, 3, 2, 1, 0]
[ ,  ,  , 0, 1, 2, 1, 1, 1, 1, 0]
[ ,  ,  ,  , 0, 1, 1, 2, 3, 4, 1, 0]
[ ,  ,  ,  ,  , 0, 1, 3, 5, 7, 2, 1, 0]
[ ,  ,  ,  ,  ,  , 0, 1, 2, 3, 1, 1, 1, 0]
[ ,  ,  ,  ,  ,  ,  , 0, 1, 2, 1, 2, 3, 1, 0]

sage: TestSuite(t).run()

sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1])
sage: path_tableaux.CylindricalDiagram(t)
[0, 1, 2, 7, 5, 3, 7, 4, 1, 0]
[ , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0]
[ ,  , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0]
[ ,  ,  , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0]
[ ,  ,  ,  , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0]
[ ,  ,  ,  ,  , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0]
[ ,  ,  ,  ,  ,  , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0]
[ ,  ,  ,  ,  ,  ,  , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0]
[ ,  ,  ,  ,  ,  ,  ,  , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0]
[ ,  ,  ,  ,  ,  ,  ,  ,  , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0]

 sage: TestSuite(t).run()

sage: t = path_tableaux.FriezePattern([1,3,4,5,1])
sage: path_tableaux.CylindricalDiagram(t)
[  0,   1,   3,   4,   5,   1,   0]
[   ,   0,   1, 5/3, 7/3, 2/3,   1,   0]
[   ,    ,   0,   1,   2,   1,   3,   1,   0]
[   ,    ,    ,   0,   1,   1,   4, 5/3,   1,   0]
[   ,    ,    ,    ,   0,   1,   5, 7/3,   2,   1,   0]
[   ,    ,    ,    ,    ,   0,   1, 2/3,   1,   1,   1,   0]
[   ,    ,    ,    ,    ,    ,   0,   1,   3,   4,   5,   1,   0]

sage: TestSuite(t).run()
>>> from sage.all import *
>>> t = path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1),Integer(2),Integer(3),Integer(1)])
>>> path_tableaux.CylindricalDiagram(t)
[0, 1, 2, 1, 2, 3, 1, 0]
[ , 0, 1, 1, 3, 5, 2, 1, 0]
[ ,  , 0, 1, 4, 7, 3, 2, 1, 0]
[ ,  ,  , 0, 1, 2, 1, 1, 1, 1, 0]
[ ,  ,  ,  , 0, 1, 1, 2, 3, 4, 1, 0]
[ ,  ,  ,  ,  , 0, 1, 3, 5, 7, 2, 1, 0]
[ ,  ,  ,  ,  ,  , 0, 1, 2, 3, 1, 1, 1, 0]
[ ,  ,  ,  ,  ,  ,  , 0, 1, 2, 1, 2, 3, 1, 0]

>>> TestSuite(t).run()

>>> t = path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(7),Integer(5),Integer(3),Integer(7),Integer(4),Integer(1)])
>>> path_tableaux.CylindricalDiagram(t)
[0, 1, 2, 7, 5, 3, 7, 4, 1, 0]
[ , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0]
[ ,  , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0]
[ ,  ,  , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0]
[ ,  ,  ,  , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0]
[ ,  ,  ,  ,  , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0]
[ ,  ,  ,  ,  ,  , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0]
[ ,  ,  ,  ,  ,  ,  , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0]
[ ,  ,  ,  ,  ,  ,  ,  , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0]
[ ,  ,  ,  ,  ,  ,  ,  ,  , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0]

>>> TestSuite(t).run()

>>> t = path_tableaux.FriezePattern([Integer(1),Integer(3),Integer(4),Integer(5),Integer(1)])
>>> path_tableaux.CylindricalDiagram(t)
[  0,   1,   3,   4,   5,   1,   0]
[   ,   0,   1, 5/3, 7/3, 2/3,   1,   0]
[   ,    ,   0,   1,   2,   1,   3,   1,   0]
[   ,    ,    ,   0,   1,   1,   4, 5/3,   1,   0]
[   ,    ,    ,    ,   0,   1,   5, 7/3,   2,   1,   0]
[   ,    ,    ,    ,    ,   0,   1, 2/3,   1,   1,   1,   0]
[   ,    ,    ,    ,    ,    ,   0,   1,   3,   4,   5,   1,   0]

>>> TestSuite(t).run()

This constructs the examples from [HJ18]:

sage: # needs sage.rings.number_field
sage: x = polygen(ZZ, 'x')
sage: K.<sqrt3> = NumberField(x^2 - 3)
sage: t = path_tableaux.FriezePattern([1, sqrt3, 2, sqrt3, 1, 1], field=K)
sage: path_tableaux.CylindricalDiagram(t)
[        0,         1,     sqrt3,         2,     sqrt3,         1,         1,         0]
[         ,         0,         1,     sqrt3,         2,     sqrt3, sqrt3 + 1,         1,         0]
[         ,          ,         0,         1,     sqrt3,         2, sqrt3 + 2,     sqrt3,         1,         0]
[         ,          ,          ,         0,         1,     sqrt3, sqrt3 + 2,         2,     sqrt3,         1,         0]
[         ,          ,          ,          ,         0,         1, sqrt3 + 1,     sqrt3,         2,     sqrt3,         1,         0]
[         ,          ,          ,          ,          ,         0,         1,         1,     sqrt3,         2,     sqrt3,         1,         0]
[         ,          ,          ,          ,          ,          ,         0,         1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1,         1,         0]
[         ,          ,          ,          ,          ,          ,          ,         0,         1,     sqrt3,         2,     sqrt3,         1,         1,         0]
sage: TestSuite(t).run()

sage: # needs sage.rings.number_field
sage: K.<sqrt2> = NumberField(x^2 - 2)
sage: t = path_tableaux.FriezePattern([1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1],
....:                                 field=K)
sage: path_tableaux.CylindricalDiagram(t)
[      0,       1,   sqrt2,       1,   sqrt2,       3, 2*sqrt2,       5, 3*sqrt2,       1,       0]
[       ,       0,       1,   sqrt2,       3, 5*sqrt2,       7, 9*sqrt2,      11, 2*sqrt2,       1,       0]
[       ,        ,       0,       1, 2*sqrt2,       7, 5*sqrt2,      13, 8*sqrt2,       3,   sqrt2,       1,       0]
[       ,        ,        ,       0,       1, 2*sqrt2,       3, 4*sqrt2,       5,   sqrt2,       1,   sqrt2,       1,       0]
[       ,        ,        ,        ,       0,       1,   sqrt2,       3, 2*sqrt2,       1,   sqrt2,       3, 2*sqrt2,       1,       0]
[       ,        ,        ,        ,        ,       0,       1, 2*sqrt2,       3,   sqrt2,       3, 5*sqrt2,       7, 2*sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,       0,       1,   sqrt2,       1, 2*sqrt2,       7, 5*sqrt2,       3,   sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,       0,       1,   sqrt2,       5, 9*sqrt2,      13, 4*sqrt2,       3, 2*sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,        ,       0,       1, 3*sqrt2,      11, 8*sqrt2,       5, 2*sqrt2,       3,   sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,        ,        ,       0,       1, 2*sqrt2,       3,   sqrt2,       1,   sqrt2,       1,   sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,        ,        ,        ,       0,       1,   sqrt2,       1,   sqrt2,       3, 2*sqrt2,       5, 3*sqrt2,       1,       0]
sage: TestSuite(t).run()
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(3), names=('sqrt3',)); (sqrt3,) = K._first_ngens(1)
>>> t = path_tableaux.FriezePattern([Integer(1), sqrt3, Integer(2), sqrt3, Integer(1), Integer(1)], field=K)
>>> path_tableaux.CylindricalDiagram(t)
[        0,         1,     sqrt3,         2,     sqrt3,         1,         1,         0]
[         ,         0,         1,     sqrt3,         2,     sqrt3, sqrt3 + 1,         1,         0]
[         ,          ,         0,         1,     sqrt3,         2, sqrt3 + 2,     sqrt3,         1,         0]
[         ,          ,          ,         0,         1,     sqrt3, sqrt3 + 2,         2,     sqrt3,         1,         0]
[         ,          ,          ,          ,         0,         1, sqrt3 + 1,     sqrt3,         2,     sqrt3,         1,         0]
[         ,          ,          ,          ,          ,         0,         1,         1,     sqrt3,         2,     sqrt3,         1,         0]
[         ,          ,          ,          ,          ,          ,         0,         1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1,         1,         0]
[         ,          ,          ,          ,          ,          ,          ,         0,         1,     sqrt3,         2,     sqrt3,         1,         1,         0]
>>> TestSuite(t).run()

>>> # needs sage.rings.number_field
>>> K = NumberField(x**Integer(2) - Integer(2), names=('sqrt2',)); (sqrt2,) = K._first_ngens(1)
>>> t = path_tableaux.FriezePattern([Integer(1), sqrt2, Integer(1), sqrt2, Integer(3), Integer(2)*sqrt2, Integer(5), Integer(3)*sqrt2, Integer(1)],
...                                 field=K)
>>> path_tableaux.CylindricalDiagram(t)
[      0,       1,   sqrt2,       1,   sqrt2,       3, 2*sqrt2,       5, 3*sqrt2,       1,       0]
[       ,       0,       1,   sqrt2,       3, 5*sqrt2,       7, 9*sqrt2,      11, 2*sqrt2,       1,       0]
[       ,        ,       0,       1, 2*sqrt2,       7, 5*sqrt2,      13, 8*sqrt2,       3,   sqrt2,       1,       0]
[       ,        ,        ,       0,       1, 2*sqrt2,       3, 4*sqrt2,       5,   sqrt2,       1,   sqrt2,       1,       0]
[       ,        ,        ,        ,       0,       1,   sqrt2,       3, 2*sqrt2,       1,   sqrt2,       3, 2*sqrt2,       1,       0]
[       ,        ,        ,        ,        ,       0,       1, 2*sqrt2,       3,   sqrt2,       3, 5*sqrt2,       7, 2*sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,       0,       1,   sqrt2,       1, 2*sqrt2,       7, 5*sqrt2,       3,   sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,       0,       1,   sqrt2,       5, 9*sqrt2,      13, 4*sqrt2,       3, 2*sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,        ,       0,       1, 3*sqrt2,      11, 8*sqrt2,       5, 2*sqrt2,       3,   sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,        ,        ,       0,       1, 2*sqrt2,       3,   sqrt2,       1,   sqrt2,       1,   sqrt2,       1,       0]
[       ,        ,        ,        ,        ,        ,        ,        ,        ,        ,       0,       1,   sqrt2,       1,   sqrt2,       3, 2*sqrt2,       5, 3*sqrt2,       1,       0]
>>> TestSuite(t).run()
change_ring(R)[source]

Return self as a frieze pattern with coefficients in R.

This assumes that there is a canonical coerce map from the base ring of self to R.

EXAMPLES:

sage: fp = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1])
sage: fp.change_ring(RealField())                                           # needs sage.rings.real_mpfr
[0.000000000000000, 1.00000000000000, ...
 4.00000000000000, 1.00000000000000, 0.000000000000000]
sage: fp.change_ring(GF(7))
Traceback (most recent call last):
...
TypeError: no base extension defined
>>> from sage.all import *
>>> fp = path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(7),Integer(5),Integer(3),Integer(7),Integer(4),Integer(1)])
>>> fp.change_ring(RealField())                                           # needs sage.rings.real_mpfr
[0.000000000000000, 1.00000000000000, ...
 4.00000000000000, 1.00000000000000, 0.000000000000000]
>>> fp.change_ring(GF(Integer(7)))
Traceback (most recent call last):
...
TypeError: no base extension defined
check()[source]

Check that self is a valid frieze pattern.

is_integral()[source]

Return True if all entries of the frieze pattern are positive integers.

EXAMPLES:

sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).is_integral()
True

sage: path_tableaux.FriezePattern([1,3,4,5,1]).is_integral()
False
>>> from sage.all import *
>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(7),Integer(5),Integer(3),Integer(7),Integer(4),Integer(1)]).is_integral()
True

>>> path_tableaux.FriezePattern([Integer(1),Integer(3),Integer(4),Integer(5),Integer(1)]).is_integral()
False
is_positive()[source]

Return True if all elements of self are positive.

This implies that all entries of CylindricalDiagram(self) are positive.

Warning

There are orders on all fields. These may not be ordered fields as they may not be compatible with the field operations. This method is intended to be used with ordered fields only.

EXAMPLES:

sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).is_positive()
True

sage: path_tableaux.FriezePattern([1,-3,4,5,1]).is_positive()
False

sage: x = polygen(ZZ, 'x')
sage: K.<sqrt3> = NumberField(x^2 - 3)                                      # needs sage.rings.number_field
sage: path_tableaux.FriezePattern([1,sqrt3,1], K).is_positive()             # needs sage.rings.number_field
True
>>> from sage.all import *
>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(7),Integer(5),Integer(3),Integer(7),Integer(4),Integer(1)]).is_positive()
True

>>> path_tableaux.FriezePattern([Integer(1),-Integer(3),Integer(4),Integer(5),Integer(1)]).is_positive()
False

>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(3), names=('sqrt3',)); (sqrt3,) = K._first_ngens(1)# needs sage.rings.number_field
>>> path_tableaux.FriezePattern([Integer(1),sqrt3,Integer(1)], K).is_positive()             # needs sage.rings.number_field
True
is_skew()[source]

Return True if self is skew and False if not.

EXAMPLES:

sage: path_tableaux.FriezePattern([1,2,1,2,3,1]).is_skew()
False

sage: path_tableaux.FriezePattern([2,2,1,2,3,1]).is_skew()
True
>>> from sage.all import *
>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1),Integer(2),Integer(3),Integer(1)]).is_skew()
False

>>> path_tableaux.FriezePattern([Integer(2),Integer(2),Integer(1),Integer(2),Integer(3),Integer(1)]).is_skew()
True
local_rule(i)[source]

Return the \(i\)-th local rule on self.

This interprets self as a list of objects. This method first takes the list of objects of length three consisting of the \((i-1)\)-st, \(i\)-th and \((i+1)\)-term and applies the rule. It then replaces the \(i\)-th object by the object returned by the rule.

EXAMPLES:

sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1])
sage: t.local_rule(3)
[1, 2, 5, 2, 3, 1]

sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1])
sage: t.local_rule(0)
Traceback (most recent call last):
...
ValueError: 0 is not a valid integer
>>> from sage.all import *
>>> t = path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1),Integer(2),Integer(3),Integer(1)])
>>> t.local_rule(Integer(3))
[1, 2, 5, 2, 3, 1]

>>> t = path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1),Integer(2),Integer(3),Integer(1)])
>>> t.local_rule(Integer(0))
Traceback (most recent call last):
...
ValueError: 0 is not a valid integer
plot(model='UHP')[source]

Plot the frieze as an ideal hyperbolic polygon.

This is only defined up to isometry of the hyperbolic plane.

We are identifying the boundary of the hyperbolic plane with the real projective line.

The option model must be one of

  • 'UHP' – (default) for the upper half plane model

  • 'PD' – for the Poincare disk model

  • 'KM' – for the Klein model

The hyperboloid model is not an option as this does not implement boundary points.

../../../_images/frieze-1.svg

EXAMPLES:

sage: # needs sage.plot sage.symbolic
sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1])
sage: t.plot()
Graphics object consisting of 18 graphics primitives
sage: t.plot(model='UHP')
Graphics object consisting of 18 graphics primitives
sage: t.plot(model='PD')
Traceback (most recent call last):
...
TypeError: '>' not supported between instances of 'NotANumber' and 'Pi'
sage: t.plot(model='KM')
Graphics object consisting of 18 graphics primitives
>>> from sage.all import *
>>> # needs sage.plot sage.symbolic
>>> t = path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(7),Integer(5),Integer(3),Integer(7),Integer(4),Integer(1)])
>>> t.plot()
Graphics object consisting of 18 graphics primitives
>>> t.plot(model='UHP')
Graphics object consisting of 18 graphics primitives
>>> t.plot(model='PD')
Traceback (most recent call last):
...
TypeError: '>' not supported between instances of 'NotANumber' and 'Pi'
>>> t.plot(model='KM')
Graphics object consisting of 18 graphics primitives
triangulation()[source]

Plot a regular polygon with some diagonals.

If self is positive and integral then this will be a triangulation.

../../../_images/frieze-2.svg

EXAMPLES:

sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation()        # needs sage.plot sage.symbolic
Graphics object consisting of 25 graphics primitives

sage: path_tableaux.FriezePattern([1,2,1/7,5,3]).triangulation()            # needs sage.plot sage.symbolic
Graphics object consisting of 12 graphics primitives


sage: x = polygen(ZZ, 'x')
sage: K.<sqrt2> = NumberField(x^2 - 2)                                      # needs sage.rings.number_field
sage: path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1],  # needs sage.plot sage.rings.number_field sage.symbolic
....:                             field=K).triangulation()
Graphics object consisting of 24 graphics primitives
>>> from sage.all import *
>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(7),Integer(5),Integer(3),Integer(7),Integer(4),Integer(1)]).triangulation()        # needs sage.plot sage.symbolic
Graphics object consisting of 25 graphics primitives

>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1)/Integer(7),Integer(5),Integer(3)]).triangulation()            # needs sage.plot sage.symbolic
Graphics object consisting of 12 graphics primitives


>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(2), names=('sqrt2',)); (sqrt2,) = K._first_ngens(1)# needs sage.rings.number_field
>>> path_tableaux.FriezePattern([Integer(1),sqrt2,Integer(1),sqrt2,Integer(3),Integer(2)*sqrt2,Integer(5),Integer(3)*sqrt2,Integer(1)],  # needs sage.plot sage.rings.number_field sage.symbolic
...                             field=K).triangulation()
Graphics object consisting of 24 graphics primitives
width()[source]

Return the width of self.

If the first and last terms of self are 1 then this is the length of self plus two and otherwise is undefined.

EXAMPLES:

sage: path_tableaux.FriezePattern([1,2,1,2,3,1]).width()
8

sage: path_tableaux.FriezePattern([1,2,1,2,3,4]).width() is None
True
>>> from sage.all import *
>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1),Integer(2),Integer(3),Integer(1)]).width()
8

>>> path_tableaux.FriezePattern([Integer(1),Integer(2),Integer(1),Integer(2),Integer(3),Integer(4)]).width() is None
True
class sage.combinat.path_tableaux.frieze.FriezePatterns(field)[source]

Bases: PathTableaux

The set of all frieze patterns.

EXAMPLES:

sage: P = path_tableaux.FriezePatterns(QQ)
sage: fp = P((1, 1, 1))
sage: fp
[1]
sage: path_tableaux.CylindricalDiagram(fp)
[1, 1, 1]
[ , 1, 2, 1]
[ ,  , 1, 1, 1]
>>> from sage.all import *
>>> P = path_tableaux.FriezePatterns(QQ)
>>> fp = P((Integer(1), Integer(1), Integer(1)))
>>> fp
[1]
>>> path_tableaux.CylindricalDiagram(fp)
[1, 1, 1]
[ , 1, 2, 1]
[ ,  , 1, 1, 1]
Element[source]

alias of FriezePattern