def b(tableau, star=0): r""" The column projection operator corresponding to the Young tableau ``tableau`` (which is supposed to contain every integer from `1` to its size precisely once, but may and may not be standard). This is the signed sum (in the group algebra of the relevant symmetric group over `\QQ`) of all the permutations which preserve the column of ``tableau`` (where the signs are the usual signs of the permutations). It is called `b_{\text{tableau}}` in [EtRT]_, Section 4.2. EXAMPLES:: sage: from sage.combinat.symmetric_group_algebra import b sage: b([[1,2]]) [1, 2] sage: b([[1],[2]]) [1, 2] - [2, 1] sage: b([]) [] sage: b([[1, 2, 4], [5, 3]]) [1, 2, 3, 4, 5] - [1, 3, 2, 4, 5] - [5, 2, 3, 4, 1] + [5, 3, 2, 4, 1] With the `l2r` setting for multiplication, the unnormalized Young symmetrizer ``e(tableau)`` should be the product ``b(tableau) * a(tableau)`` for every ``tableau``. Let us check this on the standard tableaux of size 5:: sage: from sage.combinat.symmetric_group_algebra import a, b, e sage: all( e(t) == b(t) * a(t) for t in StandardTableaux(5) ) True """ t = Tableau(tableau) if star: t = t.restrict(t.size() - star) cs = t.column_stabilizer().list() n = t.size() # This all should be over ZZ, not over QQ, but symmetric group # algebras don't seem to preserve coercion (the one over ZZ # doesn't coerce into the one over QQ even for the same n), # and the QQ version of this method is more important, so let # me stay with QQ. # TODO: Fix this. sgalg = SymmetricGroupAlgebra(QQ, n) one = QQ.one() P = permutation.Permutation # Ugly hack for the case of an empty tableau, due to the # annoyance of Permutation(Tableau([]).row_stabilizer()[0]) # being [1] rather than [] (which seems to have its origins in # permutation group code). # TODO: Fix this. if len(tableau) == 0: return sgalg.one() cd = dict((P(v), v.sign() * one) for v in cs) return sgalg._from_dict(cd)
def b(tableau, star=0): r""" The column projection operator corresponding to the Young tableau ``tableau`` (which is supposed to contain every integer from `1` to its size precisely once, but may and may not be standard). This is the signed sum (in the group algebra of the relevant symmetric group over `\QQ`) of all the permutations which preserve the column of ``tableau`` (where the signs are the usual signs of the permutations). It is called `b_{\text{tableau}}` in [EtRT]_, Section 4.2. EXAMPLES:: sage: from sage.combinat.symmetric_group_algebra import b sage: b([[1,2]]) [1, 2] sage: b([[1],[2]]) [1, 2] - [2, 1] sage: b([]) [] sage: b([[1, 2, 4], [5, 3]]) [1, 2, 3, 4, 5] - [1, 3, 2, 4, 5] - [5, 2, 3, 4, 1] + [5, 3, 2, 4, 1] With the `l2r` setting for multiplication, the unnormalized Young symmetrizer ``e(tableau)`` should be the product ``b(tableau) * a(tableau)`` for every ``tableau``. Let us check this on the standard tableaux of size 5:: sage: from sage.combinat.symmetric_group_algebra import a, b, e sage: all( e(t) == b(t) * a(t) for t in StandardTableaux(5) ) True """ t = Tableau(tableau) if star: t = t.restrict(t.size()-star) cs = t.column_stabilizer().list() n = t.size() # This all should be over ZZ, not over QQ, but symmetric group # algebras don't seem to preserve coercion (the one over ZZ # doesn't coerce into the one over QQ even for the same n), # and the QQ version of this method is more important, so let # me stay with QQ. # TODO: Fix this. sgalg = SymmetricGroupAlgebra(QQ, n) one = QQ.one() P = permutation.Permutation # Ugly hack for the case of an empty tableau, due to the # annoyance of Permutation(Tableau([]).row_stabilizer()[0]) # being [1] rather than [] (which seems to have its origins in # permutation group code). # TODO: Fix this. if len(tableau) == 0: return sgalg.one() cd = dict((P(v), v.sign()*one) for v in cs) return sgalg._from_dict(cd)
def a(tableau, star=0): r""" The row projection operator corresponding to the Young tableau ``tableau`` (which is supposed to contain every integer from `1` to its size precisely once, but may and may not be standard). This is the sum (in the group algebra of the relevant symmetric group over `\QQ`) of all the permutations which preserve the rows of ``tableau``. It is called `a_{\text{tableau}}` in [EtRT]_, Section 4.2. REFERENCES: .. [EtRT] Pavel Etingof, Oleg Golberg, Sebastian Hensel, Tiankai Liu, Alex Schwendner, Dmitry Vaintrob, Elena Yudovina, "Introduction to representation theory", :arXiv:`0901.0827v5`. EXAMPLES:: sage: from sage.combinat.symmetric_group_algebra import a sage: a([[1,2]]) [1, 2] + [2, 1] sage: a([[1],[2]]) [1, 2] sage: a([]) [] sage: a([[1, 5], [2, 3], [4]]) [1, 2, 3, 4, 5] + [1, 3, 2, 4, 5] + [5, 2, 3, 4, 1] + [5, 3, 2, 4, 1] """ t = Tableau(tableau) if star: t = t.restrict(t.size() - star) rs = t.row_stabilizer().list() n = t.size() # This all should be over ZZ, not over QQ, but symmetric group # algebras don't seem to preserve coercion (the one over ZZ # doesn't coerce into the one over QQ even for the same n), # and the QQ version of this method is more important, so let # me stay with QQ. # TODO: Fix this. sgalg = SymmetricGroupAlgebra(QQ, n) one = QQ.one() P = permutation.Permutation # Ugly hack for the case of an empty tableau, due to the # annoyance of Permutation(Tableau([]).row_stabilizer()[0]) # being [1] rather than [] (which seems to have its origins in # permutation group code). # TODO: Fix this. if len(tableau) == 0: return sgalg.one() rd = dict((P(h), one) for h in rs) return sgalg._from_dict(rd)
def a(tableau, star=0): r""" The row projection operator corresponding to the Young tableau ``tableau`` (which is supposed to contain every integer from `1` to its size precisely once, but may and may not be standard). This is the sum (in the group algebra of the relevant symmetric group over `\QQ`) of all the permutations which preserve the rows of ``tableau``. It is called `a_{\text{tableau}}` in [EtRT]_, Section 4.2. REFERENCES: .. [EtRT] Pavel Etingof, Oleg Golberg, Sebastian Hensel, Tiankai Liu, Alex Schwendner, Dmitry Vaintrob, Elena Yudovina, "Introduction to representation theory", :arXiv:`0901.0827v5`. EXAMPLES:: sage: from sage.combinat.symmetric_group_algebra import a sage: a([[1,2]]) [1, 2] + [2, 1] sage: a([[1],[2]]) [1, 2] sage: a([]) [] sage: a([[1, 5], [2, 3], [4]]) [1, 2, 3, 4, 5] + [1, 3, 2, 4, 5] + [5, 2, 3, 4, 1] + [5, 3, 2, 4, 1] """ t = Tableau(tableau) if star: t = t.restrict(t.size()-star) rs = t.row_stabilizer().list() n = t.size() # This all should be over ZZ, not over QQ, but symmetric group # algebras don't seem to preserve coercion (the one over ZZ # doesn't coerce into the one over QQ even for the same n), # and the QQ version of this method is more important, so let # me stay with QQ. # TODO: Fix this. sgalg = SymmetricGroupAlgebra(QQ, n) one = QQ.one() P = permutation.Permutation # Ugly hack for the case of an empty tableau, due to the # annoyance of Permutation(Tableau([]).row_stabilizer()[0]) # being [1] rather than [] (which seems to have its origins in # permutation group code). # TODO: Fix this. if len(tableau) == 0: return sgalg.one() rd = dict((P(h), one) for h in rs) return sgalg._from_dict(rd)
def rotation_matrix_angle(r, check=False): r""" Return the angle of the rotation matrix ``r`` divided by ``2 pi``. EXAMPLES:: sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle sage: def rot_matrix(p, q): ....: z = QQbar.zeta(q) ** p ....: c = z.real() ....: s = z.imag() ....: return matrix(AA, 2, [c,-s,s,c]) sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)] [1/5, 2/5, 3/5, 4/5] sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)] [1/5, 2/5, 3/5, 4/5] sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)] [1/7, 2/7, 3/7, 4/7, 5/7, 6/7] Some random tests:: sage: for _ in range(100): ....: r = QQ.random_element(x=0,y=500) ....: r -= r.floor() ....: m = rot_matrix(r.numerator(), r.denominator()) ....: assert rotation_matrix_angle(m) == r .. NOTE:: This is using floating point arithmetic and might be wrong. """ e0, e1 = r.change_ring(CDF).eigenvalues() m0 = (e0.log() / 2 / CDF.pi()).imag() m1 = (e1.log() / 2 / CDF.pi()).imag() r0 = RR(m0).nearby_rational(max_denominator=10000) r1 = RR(m1).nearby_rational(max_denominator=10000) if r0 != -r1: raise RuntimeError r0 = r0.abs() if r[0][1] > 0: return QQ.one() - r0 else: return r0 if check: e = r.change_ring(AA).eigenvalues()[0] if e.minpoly() != ZZ['x'].cyclotomic_polynomial()(r.denominator()): raise RuntimeError z = QQbar.zeta(r.denominator()) if z**r.numerator() != e: raise RuntimeError return r
def coeff(p, q): ret = QQ.one() last = 0 for val in p: count = 0 s = 0 while s != val: s += q[last+count] count += 1 ret /= factorial(count) last += count return ret
def coeff(p, q): ret = QQ.one() last = 0 for val in p: count = 0 s = 0 while s != val: s += q[last + count] count += 1 ret /= factorial(count) last += count return ret
def rotation_matrix_angle(r, check=False): r""" Return the angle of the rotation matrix ``r`` divided by ``2 pi``. EXAMPLES:: sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle sage: def rot_matrix(p, q): ....: z = QQbar.zeta(q) ** p ....: c = z.real() ....: s = z.imag() ....: return matrix(AA, 2, [c,-s,s,c]) sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)] [1/5, 2/5, 3/5, 4/5] sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)] [1/7, 2/7, 3/7, 4/7, 5/7, 6/7] Some random tests:: sage: for _ in range(100): ....: r = QQ.random_element(x=0,y=500) ....: r -= r.floor() ....: m = rot_matrix(r.numerator(), r.denominator()) ....: assert rotation_matrix_angle(m) == r .. NOTE:: This is using floating point arithmetic and might be wrong. """ e0,e1 = r.change_ring(CDF).eigenvalues() m0 = (e0.log() / 2 / CDF.pi()).imag() m1 = (e1.log() / 2 / CDF.pi()).imag() r0 = RR(m0).nearby_rational(max_denominator=10000) r1 = RR(m1).nearby_rational(max_denominator=10000) if r0 != -r1: raise RuntimeError r0 = r0.abs() if r[0][1] > 0: return QQ.one() - r0 else: return r0 if check: e = r.change_ring(AA).eigenvalues()[0] if e.minpoly() != ZZ['x'].cyclotomic_polynomial()(r.denominator()): raise RuntimeError z = QQbar.zeta(r.denominator()) if z**r.numerator() != e: raise RuntimeError return r
def coeff(p, q): ret = QQ.one() last = 0 for val in p: count = 0 s = 0 while s != val: s += q[last+count] count += 1 ret /= count last += count if (len(q) - len(p)) % 2 == 1: ret = -ret return ret
def coeff(p, q): ret = QQ.one() last = 0 for val in p: count = 0 s = 0 while s != val: s += q[last + count] count += 1 ret /= count last += count if (len(q) - len(p)) % 2 == 1: ret = -ret return ret
def one(self): r""" EXAMPLES:: sage: from surface_dynamics.misc.multiplicative_multivariate_generating_series import MultiplicativeMultivariateGeneratingSeriesRing sage: M = MultiplicativeMultivariateGeneratingSeriesRing('x', 2) sage: M.zero() 0 sage: M.zero().parent() is M True sage: M.one().is_one() True """ return self._element_constructor_(QQ.one())
def e(tableau, star=0): """ The unnormalized Young projection operator corresponding to the Young tableau ``tableau`` (which is supposed to contain every integer from `1` to its size precisely once, but may and may not be standard). EXAMPLES:: sage: from sage.combinat.symmetric_group_algebra import e sage: e([[1,2]]) [1, 2] + [2, 1] sage: e([[1],[2]]) [1, 2] - [2, 1] sage: e([]) [] There are differing conventions for the order of the symmetrizers and antisymmetrizers. This example illustrates our conventions:: sage: e([[1,2],[3]]) [1, 2, 3] + [2, 1, 3] - [3, 1, 2] - [3, 2, 1] """ t = Tableau(tableau) if star: t = t.restrict(t.size() - star) mult = permutation_options['mult'] permutation_options['mult'] = 'l2r' if t in e_cache: res = e_cache[t] else: rs = t.row_stabilizer().list() cs = t.column_stabilizer().list() n = t.size() QSn = SymmetricGroupAlgebra(QQ, n) one = QQ.one() P = permutation.Permutation rd = dict((P(h), one) for h in rs) sym = QSn._from_dict(rd) cd = dict((P(v), v.sign() * one) for v in cs) antisym = QSn._from_dict(cd) res = antisym * sym # Ugly hack for the case of an empty tableau, due to the # annoyance of Permutation(Tableau([]).row_stabilizer()[0]) # being [1] rather than [] (which seems to have its origins in # permutation group code). # TODO: Fix this. if len(tableau) == 0: res = QSn.one() e_cache[t] = res permutation_options['mult'] = mult return res
def e(tableau, star=0): """ The unnormalized Young projection operator corresponding to the Young tableau ``tableau`` (which is supposed to contain every integer from `1` to its size precisely once, but may and may not be standard). EXAMPLES:: sage: from sage.combinat.symmetric_group_algebra import e sage: e([[1,2]]) [1, 2] + [2, 1] sage: e([[1],[2]]) [1, 2] - [2, 1] sage: e([]) [] There are differing conventions for the order of the symmetrizers and antisymmetrizers. This example illustrates our conventions:: sage: e([[1,2],[3]]) [1, 2, 3] + [2, 1, 3] - [3, 1, 2] - [3, 2, 1] """ t = Tableau(tableau) if star: t = t.restrict(t.size()-star) mult = permutation_options['mult'] permutation_options['mult'] = 'l2r' if t in e_cache: res = e_cache[t] else: rs = t.row_stabilizer().list() cs = t.column_stabilizer().list() n = t.size() QSn = SymmetricGroupAlgebra(QQ, n) one = QQ.one() P = permutation.Permutation rd = dict((P(h), one) for h in rs) sym = QSn._from_dict(rd) cd = dict((P(v), v.sign()*one) for v in cs) antisym = QSn._from_dict(cd) res = antisym*sym # Ugly hack for the case of an empty tableau, due to the # annoyance of Permutation(Tableau([]).row_stabilizer()[0]) # being [1] rather than [] (which seems to have its origins in # permutation group code). # TODO: Fix this. if len(tableau) == 0: res = QSn.one() e_cache[t] = res permutation_options['mult'] = mult return res