Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/cyclic_sieving_phenomenon.py
4091 views
1
r"""
2
Cyclic sieving phenomenon
3
4
Implementation of the Cyclic Sieving Phenomenon as described in
5
Reiner, Stanton, White - The cyclic sieving phenomenon, Journal of Combinatorial Theory A 108 (2004)
6
7
We define the CyclicSievingPolynomial of a finite set S together with cyclic action cyc_act (of order n) to be the unique
8
polynomial P(q) of order < n such that the triple ( S, cyc_act, P(q) ) exhibits the cyclic sieving phenomenon.
9
10
AUTHORS:
11
12
- Christian Stump
13
"""
14
#*****************************************************************************
15
# Copyright (C) 2010 Christian Stump [email protected]
16
#
17
# Distributed under the terms of the GNU General Public License (GPL)
18
# http://www.gnu.org/licenses/
19
#*****************************************************************************
20
21
from copy import copy
22
from sage.rings.all import ZZ, QQ
23
from sage.rings.arith import lcm
24
25
def CyclicSievingPolynomial( L, cyc_act=None, order=None, get_order=False):
26
"""
27
Returns the unique polynomial p of degree smaller than order such that the triple
28
( L, cyc_act, p ) exhibits the CSP. If ``cyc_act`` is None, ``L`` is expected to contain the orbit lengths.
29
30
INPUT:
31
32
- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects
33
34
- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L)
35
36
- 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)
37
otherwise, the order of cyc_action is used
38
39
- get_order -- (default:False) if True, a tuple [p,n] is returned where p as above, and n is the order
40
41
EXAMPLES::
42
43
sage: from sage.combinat.cyclic_sieving_phenomenon import CyclicSievingPolynomial
44
sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42
45
[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]
46
sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)
47
sage: cyc_act([1,3])
48
{2, 4}
49
sage: cyc_act([1,4])
50
{1, 2}
51
sage: CyclicSievingPolynomial( S42, cyc_act )
52
q^3 + 2*q^2 + q + 2
53
sage: CyclicSievingPolynomial( S42, cyc_act, get_order=True )
54
[q^3 + 2*q^2 + q + 2, 4]
55
sage: CyclicSievingPolynomial( S42, cyc_act, order=8 )
56
q^6 + 2*q^4 + q^2 + 2
57
sage: CyclicSievingPolynomial([4,2])
58
q^3 + 2*q^2 + q + 2
59
"""
60
61
if cyc_act:
62
orbits = orbit_decomposition( L, cyc_act )
63
else:
64
orbits = [ range(k) for k in L ]
65
66
R = QQ['q']
67
q = R.gen()
68
p = R(0)
69
70
orbit_sizes = {}
71
for orbit in orbits:
72
l = len( orbit )
73
if l in orbit_sizes:
74
orbit_sizes[ l ] += 1
75
else:
76
orbit_sizes[ l ] = 1
77
78
keys = orbit_sizes.keys()
79
80
n = lcm( keys )
81
82
if order:
83
if order.mod(n) != 0:
84
raise ValueError, "The given order is not valid as it is not a multiple of the order of the given cyclic action"
85
else:
86
m = ZZ(order/n)
87
88
for i in range(n):
89
if i == 0:
90
j = sum( orbit_sizes[ l ] for l in keys )
91
else:
92
j = sum( orbit_sizes[ l ] for l in keys if ZZ(i).mod(n/l) == 0 )
93
p += j*q**i
94
95
if order:
96
p = p(q**m)
97
98
if get_order:
99
return [p,n]
100
else:
101
return p
102
103
def CyclicSievingCheck( L, cyc_act, f, order=None ):
104
"""
105
Returns 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.
106
107
INPUT:
108
109
- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects
110
111
- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L)
112
113
- 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)
114
otherwise, the order of cyc_action is used
115
116
EXAMPLES::
117
118
sage: from sage.combinat.cyclic_sieving_phenomenon import *
119
sage: from sage.combinat.q_analogues import q_binomial
120
sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42
121
[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]
122
sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)
123
sage: cyc_act([1,3])
124
{2, 4}
125
sage: cyc_act([1,4])
126
{1, 2}
127
sage: p = q_binomial(4,2); p
128
q^4 + q^3 + 2*q^2 + q + 1
129
sage: CyclicSievingPolynomial( S42, cyc_act )
130
q^3 + 2*q^2 + q + 2
131
sage: CyclicSievingCheck( S42, cyc_act, p )
132
True
133
"""
134
p1,n = CyclicSievingPolynomial( L, cyc_act=cyc_act, order=order, get_order=True )
135
R = p1.parent()
136
q = R.gen()
137
p2 = R(f).mod(q**n-1)
138
return p1 == p2
139
140
def orbit_decomposition( L, cyc_act ):
141
"""
142
Returns the orbit decomposition of L by the action of cyc_act
143
144
INPUT:
145
146
- L -- list
147
148
- cyc_act -- function taking an element of L and returning an element of L (must define a bijection on L)
149
150
OUTPUT:
151
152
- a list of lists, the orbits under the cyc_act acting on L
153
154
EXAMPLES::
155
156
sage: from sage.combinat.cyclic_sieving_phenomenon import *
157
sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42
158
[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}]
159
sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S)
160
sage: cyc_act([1,3])
161
{2, 4}
162
sage: cyc_act([1,4])
163
{1, 2}
164
sage: orbit_decomposition( S42, cyc_act )
165
[[{1, 2}, {2, 3}, {3, 4}, {1, 4}], [{1, 3}, {2, 4}]]
166
"""
167
orbits = []
168
L_prime = copy( L )
169
while L_prime <> []:
170
orbit = []
171
obj = L_prime[0]
172
while obj in L_prime:
173
orbit.append( obj )
174
L_prime.remove( obj )
175
obj = cyc_act( obj )
176
orbits.append( orbit )
177
return orbits
178
179