Path: blob/master/src/sage/combinat/cyclic_sieving_phenomenon.py
8817 views
r"""1Cyclic sieving phenomenon23Implementation of the Cyclic Sieving Phenomenon as described in4Reiner, Stanton, White - The cyclic sieving phenomenon, Journal of Combinatorial Theory A 108 (2004)56We define the CyclicSievingPolynomial of a finite set S together with cyclic action cyc_act (of order n) to be the unique7polynomial P(q) of order < n such that the triple ( S, cyc_act, P(q) ) exhibits the cyclic sieving phenomenon.89AUTHORS:1011- Christian Stump12"""13#*****************************************************************************14# Copyright (C) 2010 Christian Stump [email protected]15#16# Distributed under the terms of the GNU General Public License (GPL)17# http://www.gnu.org/licenses/18#*****************************************************************************1920from copy import copy21from sage.rings.all import ZZ, QQ22from sage.rings.arith import lcm2324def CyclicSievingPolynomial( L, cyc_act=None, order=None, get_order=False):25"""26Returns the unique polynomial p of degree smaller than order such that the triple27( L, cyc_act, p ) exhibits the CSP. If ``cyc_act`` is None, ``L`` is expected to contain the orbit lengths.2829INPUT:3031- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects3233- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L)3435- order -- (default:None) if set to an integer, this cyclic order of cyc_act is used (must be an integer multiple of the order of cyc_act)36otherwise, the order of cyc_action is used3738- get_order -- (default:False) if True, a tuple [p,n] is returned where p as above, and n is the order3940EXAMPLES::4142sage: from sage.combinat.cyclic_sieving_phenomenon import CyclicSievingPolynomial43sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S4244[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]45sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)46sage: cyc_act([1,3])47{2, 4}48sage: cyc_act([1,4])49{1, 2}50sage: CyclicSievingPolynomial( S42, cyc_act )51q^3 + 2*q^2 + q + 252sage: CyclicSievingPolynomial( S42, cyc_act, get_order=True )53[q^3 + 2*q^2 + q + 2, 4]54sage: CyclicSievingPolynomial( S42, cyc_act, order=8 )55q^6 + 2*q^4 + q^2 + 256sage: CyclicSievingPolynomial([4,2])57q^3 + 2*q^2 + q + 25859TESTS:6061We check that :trac:`13997` is handled::6263sage: CyclicSievingPolynomial( S42, cyc_act, order=8, get_order=True )64[q^6 + 2*q^4 + q^2 + 2, 8]65"""6667if cyc_act:68orbits = orbit_decomposition( L, cyc_act )69else:70orbits = [ range(k) for k in L ]7172R = QQ['q']73q = R.gen()74p = R(0)7576orbit_sizes = {}77for orbit in orbits:78l = len( orbit )79if l in orbit_sizes:80orbit_sizes[ l ] += 181else:82orbit_sizes[ l ] = 18384keys = orbit_sizes.keys()8586n = lcm( keys )8788if order:89if order.mod(n) != 0:90raise ValueError("The given order is not valid as it is not a multiple of the order of the given cyclic action")91else:92order = n9394for i in range(n):95if i == 0:96j = sum( orbit_sizes[ l ] for l in keys )97else:98j = sum( orbit_sizes[ l ] for l in keys if ZZ(i).mod(n/l) == 0 )99p += j*q**i100101p = p(q**ZZ(order/n))102103if get_order:104return [p,order]105else:106return p107108def CyclicSievingCheck( L, cyc_act, f, order=None ):109"""110Returns True if the triple ( L, cyc_act, f ) exhibits the cyclic sieving phenomenon. If cyc_act is None, L is expected to obtain the orbit lengths.111112INPUT:113114- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects115116- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L)117118- order -- (default:None) if set to an integer, this cyclic order of cyc_act is used (must be an integer multiple of the order of cyc_act)119otherwise, the order of cyc_action is used120121EXAMPLES::122123sage: from sage.combinat.cyclic_sieving_phenomenon import *124sage: from sage.combinat.q_analogues import q_binomial125sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42126[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]127sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)128sage: cyc_act([1,3])129{2, 4}130sage: cyc_act([1,4])131{1, 2}132sage: p = q_binomial(4,2); p133q^4 + q^3 + 2*q^2 + q + 1134sage: CyclicSievingPolynomial( S42, cyc_act )135q^3 + 2*q^2 + q + 2136sage: CyclicSievingCheck( S42, cyc_act, p )137True138"""139p1,n = CyclicSievingPolynomial( L, cyc_act=cyc_act, order=order, get_order=True )140R = p1.parent()141q = R.gen()142p2 = R(f).mod(q**n-1)143return p1 == p2144145def orbit_decomposition( L, cyc_act ):146"""147Returns the orbit decomposition of L by the action of cyc_act148149INPUT:150151- L -- list152153- cyc_act -- function taking an element of L and returning an element of L (must define a bijection on L)154155OUTPUT:156157- a list of lists, the orbits under the cyc_act acting on L158159EXAMPLES::160161sage: from sage.combinat.cyclic_sieving_phenomenon import *162sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42163[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]164sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)165sage: cyc_act([1,3])166{2, 4}167sage: cyc_act([1,4])168{1, 2}169sage: orbit_decomposition( S42, cyc_act )170[[{2, 4}, {1, 3}], [{1, 2}, {2, 3}, {3, 4}, {1, 4}]]171"""172orbits = []173L_prime = set(L)174while L_prime != set():175obj = L_prime.pop()176orbit = [obj]177obj = cyc_act( obj )178while obj in L_prime:179orbit.append( obj )180L_prime.remove( obj )181obj = cyc_act( obj )182orbits.append( orbit )183return orbits184185186