Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

r""" 

Cyclic sieving phenomenon 

 

Implementation of the Cyclic Sieving Phenomenon as described in 

Reiner, Stanton, White - The cyclic sieving phenomenon, Journal of Combinatorial Theory A 108 (2004) 

 

We define the CyclicSievingPolynomial of a finite set S together with cyclic action cyc_act (of order n) to be the unique 

polynomial P(q) of order < n such that the triple ( S, cyc_act, P(q) ) exhibits the cyclic sieving phenomenon. 

 

AUTHORS: 

 

- Christian Stump 

""" 

#***************************************************************************** 

# Copyright (C) 2010 Christian Stump christian.stump@univie.ac.at 

# 

# Distributed under the terms of the GNU General Public License (GPL) 

# http://www.gnu.org/licenses/ 

#***************************************************************************** 

from six.moves import range 

from sage.rings.all import ZZ, QQ 

from sage.arith.all import lcm 

 

 

def CyclicSievingPolynomial(L, cyc_act=None, order=None, get_order=False): 

""" 

Returns the unique polynomial p of degree smaller than order such that the triple 

( L, cyc_act, p ) exhibits the CSP. If ``cyc_act`` is None, ``L`` is expected to contain the orbit lengths. 

 

INPUT: 

 

- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects 

 

- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L) 

 

- 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) 

otherwise, the order of cyc_action is used 

 

- get_order -- (default:False) if True, a tuple [p,n] is returned where p as above, and n is the order 

 

EXAMPLES:: 

 

sage: from sage.combinat.cyclic_sieving_phenomenon import CyclicSievingPolynomial 

sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42 

[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}] 

sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S) 

sage: cyc_act([1,3]) 

{2, 4} 

sage: cyc_act([1,4]) 

{1, 2} 

sage: CyclicSievingPolynomial( S42, cyc_act ) 

q^3 + 2*q^2 + q + 2 

sage: CyclicSievingPolynomial( S42, cyc_act, get_order=True ) 

[q^3 + 2*q^2 + q + 2, 4] 

sage: CyclicSievingPolynomial( S42, cyc_act, order=8 ) 

q^6 + 2*q^4 + q^2 + 2 

sage: CyclicSievingPolynomial([4,2]) 

q^3 + 2*q^2 + q + 2 

 

TESTS: 

 

We check that :trac:`13997` is handled:: 

 

sage: CyclicSievingPolynomial( S42, cyc_act, order=8, get_order=True ) 

[q^6 + 2*q^4 + q^2 + 2, 8] 

""" 

if cyc_act: 

orbits = orbit_decomposition( L, cyc_act ) 

else: 

orbits = [list(range(k)) for k in L] 

 

R = QQ['q'] 

q = R.gen() 

p = R(0) 

 

orbit_sizes = {} 

for orbit in orbits: 

l = len(orbit) 

if l in orbit_sizes: 

orbit_sizes[l] += 1 

else: 

orbit_sizes[l] = 1 

 

n = lcm(list(orbit_sizes)) 

 

if order: 

if order.mod(n) != 0: 

raise ValueError("The given order is not valid as it is not a multiple of the order of the given cyclic action") 

else: 

order = n 

 

for i in range(n): 

if i == 0: 

j = sum(orbit_sizes.values()) 

else: 

j = sum(orbit_sizes[l] for l in orbit_sizes if ZZ(i).mod(n/l) == 0) 

p += j*q**i 

 

p = p(q**ZZ(order/n)) 

 

if get_order: 

return [p, order] 

else: 

return p 

 

 

def CyclicSievingCheck( L, cyc_act, f, order=None ): 

""" 

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. 

 

INPUT: 

 

- L -- if cyc_act is None: list of orbit sizes, otherwise list of objects 

 

- cyc_act -- (default:None) function taking an element of L and returning an element of L (must define a bijection on L) 

 

- 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) 

otherwise, the order of cyc_action is used 

 

EXAMPLES:: 

 

sage: from sage.combinat.cyclic_sieving_phenomenon import * 

sage: from sage.combinat.q_analogues import q_binomial 

sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42 

[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}] 

sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S) 

sage: cyc_act([1,3]) 

{2, 4} 

sage: cyc_act([1,4]) 

{1, 2} 

sage: p = q_binomial(4,2); p 

q^4 + q^3 + 2*q^2 + q + 1 

sage: CyclicSievingPolynomial( S42, cyc_act ) 

q^3 + 2*q^2 + q + 2 

sage: CyclicSievingCheck( S42, cyc_act, p ) 

True 

""" 

p1,n = CyclicSievingPolynomial( L, cyc_act=cyc_act, order=order, get_order=True ) 

R = p1.parent() 

q = R.gen() 

p2 = R(f).mod(q**n-1) 

return p1 == p2 

 

def orbit_decomposition( L, cyc_act ): 

""" 

Returns the orbit decomposition of L by the action of cyc_act 

 

INPUT: 

 

- L -- list 

 

- cyc_act -- function taking an element of L and returning an element of L (must define a bijection on L) 

 

OUTPUT: 

 

- a list of lists, the orbits under the cyc_act acting on L 

 

EXAMPLES:: 

 

sage: from sage.combinat.cyclic_sieving_phenomenon import * 

sage: S42 = [ Set(S) for S in subsets([1,2,3,4]) if len(S) == 2 ]; S42 

[{1, 2}, {1, 3}, {2, 3}, {1, 4}, {2, 4}, {3, 4}] 

sage: cyc_act = lambda S: Set( i.mod(4)+1 for i in S) 

sage: cyc_act([1,3]) 

{2, 4} 

sage: cyc_act([1,4]) 

{1, 2} 

sage: orbit_decomposition( S42, cyc_act ) 

[[{2, 4}, {1, 3}], [{1, 2}, {2, 3}, {3, 4}, {1, 4}]] 

""" 

orbits = [] 

L_prime = set(L) 

while L_prime != set(): 

obj = L_prime.pop() 

orbit = [obj] 

obj = cyc_act( obj ) 

while obj in L_prime: 

orbit.append( obj ) 

L_prime.remove( obj ) 

obj = cyc_act( obj ) 

orbits.append( orbit ) 

return orbits