Path: blob/master/sage/combinat/cyclic_sieving_phenomenon.py
4091 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 + 258"""5960if cyc_act:61orbits = orbit_decomposition( L, cyc_act )62else:63orbits = [ range(k) for k in L ]6465R = QQ['q']66q = R.gen()67p = R(0)6869orbit_sizes = {}70for orbit in orbits:71l = len( orbit )72if l in orbit_sizes:73orbit_sizes[ l ] += 174else:75orbit_sizes[ l ] = 17677keys = orbit_sizes.keys()7879n = lcm( keys )8081if order:82if order.mod(n) != 0:83raise ValueError, "The given order is not valid as it is not a multiple of the order of the given cyclic action"84else:85m = ZZ(order/n)8687for i in range(n):88if i == 0:89j = sum( orbit_sizes[ l ] for l in keys )90else:91j = sum( orbit_sizes[ l ] for l in keys if ZZ(i).mod(n/l) == 0 )92p += j*q**i9394if order:95p = p(q**m)9697if get_order:98return [p,n]99else:100return p101102def CyclicSievingCheck( L, cyc_act, f, order=None ):103"""104Returns 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.105106INPUT:107108- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects109110- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L)111112- 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)113otherwise, the order of cyc_action is used114115EXAMPLES::116117sage: from sage.combinat.cyclic_sieving_phenomenon import *118sage: from sage.combinat.q_analogues import q_binomial119sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42120[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]121sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)122sage: cyc_act([1,3])123{2, 4}124sage: cyc_act([1,4])125{1, 2}126sage: p = q_binomial(4,2); p127q^4 + q^3 + 2*q^2 + q + 1128sage: CyclicSievingPolynomial( S42, cyc_act )129q^3 + 2*q^2 + q + 2130sage: CyclicSievingCheck( S42, cyc_act, p )131True132"""133p1,n = CyclicSievingPolynomial( L, cyc_act=cyc_act, order=order, get_order=True )134R = p1.parent()135q = R.gen()136p2 = R(f).mod(q**n-1)137return p1 == p2138139def orbit_decomposition( L, cyc_act ):140"""141Returns the orbit decomposition of L by the action of cyc_act142143INPUT:144145- L -- list146147- cyc_act -- function taking an element of L and returning an element of L (must define a bijection on L)148149OUTPUT:150151- a list of lists, the orbits under the cyc_act acting on L152153EXAMPLES::154155sage: from sage.combinat.cyclic_sieving_phenomenon import *156sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42157[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]158sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)159sage: cyc_act([1,3])160{2, 4}161sage: cyc_act([1,4])162{1, 2}163sage: orbit_decomposition( S42, cyc_act )164[[{1, 2}, {2, 3}, {3, 4}, {1, 4}], [{1, 3}, {2, 4}]]165"""166orbits = []167L_prime = copy( L )168while L_prime <> []:169orbit = []170obj = L_prime[0]171while obj in L_prime:172orbit.append( obj )173L_prime.remove( obj )174obj = cyc_act( obj )175orbits.append( orbit )176return orbits177178179