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 offield
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 inR
.This assumes that there is a canonical coerce map from the base ring of
self
toR
.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
- 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 ofself
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
ifself
is skew andFalse
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.
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.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 ofself
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