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

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

r""" 

The modular group `{\rm SL}_2(\ZZ)` 

 

AUTHORS: 

 

- Niles Johnson (2010-08): :trac:`3893`: ``random_element()`` should pass on ``*args`` and ``**kwds``. 

 

""" 

from __future__ import absolute_import 

 

################################################################################ 

# 

# Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/ 

# 

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

# 

# The full text of the GPL is available at: 

# 

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

# 

################################################################################ 

 

from .congroup_gamma0 import Gamma0_class 

from .arithgroup_element import ArithmeticSubgroupElement 

from sage.rings.integer_ring import ZZ 

from sage.modular.cusps import Cusp 

from sage.arith.all import gcd 

from sage.modular.modsym.p1list import lift_to_sl2z 

 

def is_SL2Z(x): 

r""" 

Return True if x is the modular group `{\rm SL}_2(\ZZ)`. 

 

EXAMPLES:: 

 

sage: from sage.modular.arithgroup.all import is_SL2Z 

sage: is_SL2Z(SL2Z) 

True 

sage: is_SL2Z(Gamma0(6)) 

False 

""" 

return isinstance(x, SL2Z_class) 

 

class SL2Z_class(Gamma0_class): 

r""" 

The full modular group `{\rm SL}_2(\ZZ)`, regarded as a congruence 

subgroup of itself. 

""" 

 

def __init__(self): 

r""" 

The modular group ${\rm SL}_2(\Z)$. 

 

EXAMPLES:: 

 

sage: G = SL2Z; G 

Modular Group SL(2,Z) 

sage: G.gens() 

( 

[ 0 -1] [1 1] 

[ 1 0], [0 1] 

) 

sage: G.0 

[ 0 -1] 

[ 1 0] 

sage: G.1 

[1 1] 

[0 1] 

sage: latex(G) 

\mbox{\rm SL}_2(\Bold{Z}) 

sage: G([1,-1,0,1]) 

[ 1 -1] 

[ 0 1] 

sage: TestSuite(G).run() 

sage: SL2Z.0 * SL2Z.1 

[ 0 -1] 

[ 1 1] 

sage: SL2Z is loads(dumps(SL2Z)) 

True 

""" 

Gamma0_class.__init__(self, 1) 

 

def __reduce__(self): 

""" 

Used for pickling self. 

 

EXAMPLES:: 

 

sage: SL2Z.__reduce__() 

(<function _SL2Z_ref at ...>, ()) 

""" 

return _SL2Z_ref, () 

 

def _element_constructor_(self, x, check=True): 

r""" 

Create an element of self from x, which must be something that can be 

coerced into a 2x2 integer matrix. If check=True (the default), check 

that x really has determinant 1. 

 

EXAMPLES:: 

 

sage: SL2Z([1,0,0,1]) # indirect doctest 

[1 0] 

[0 1] 

sage: SL2Z([2, 0, 0, 2], check=False) # don't do this! 

[2 0] 

[0 2] 

sage: SL2Z([1, QQ, False], check=False) # don't do this either! 

Traceback (most recent call last): 

... 

TypeError: cannot construct an element of Full MatrixSpace of 2 by 2 

dense matrices over Integer Ring from [1, Rational Field, False]! 

""" 

return ArithmeticSubgroupElement(self, x, check=check) 

 

def _contains_sl2(self,a,b,c,d): 

r""" 

Test whether [a,b,c,d] is an element of self, where a,b,c,d are integers with `ad-bc=1`. In other words, always return True. 

 

EXAMPLES:: 

 

sage: [8,7,9,8] in SL2Z # indirect doctest 

True 

""" 

return True 

 

def _repr_(self): 

""" 

Return the string representation of self. 

 

EXAMPLES:: 

 

sage: SL2Z._repr_() 

'Modular Group SL(2,Z)' 

""" 

return "Modular Group SL(2,Z)" 

 

def _latex_(self): 

r""" 

Return the \LaTeX representation of self. 

 

EXAMPLES:: 

 

sage: SL2Z._latex_() 

'\\mbox{\\rm SL}_2(\\Bold{Z})' 

sage: latex(SL2Z) 

\mbox{\rm SL}_2(\Bold{Z}) 

""" 

return "\\mbox{\\rm SL}_2(%s)"%(ZZ._latex_()) 

 

def is_subgroup(self, right): 

""" 

Return True if self is a subgroup of right. 

 

EXAMPLES:: 

 

sage: SL2Z.is_subgroup(SL2Z) 

True 

sage: SL2Z.is_subgroup(Gamma1(1)) 

True 

sage: SL2Z.is_subgroup(Gamma0(6)) 

False 

""" 

return right.level() == 1 

 

def reduce_cusp(self, c): 

r""" 

Return the unique reduced cusp equivalent to c under the 

action of self. Always returns Infinity, since there is only 

one equivalence class of cusps for $SL_2(Z)$. 

 

EXAMPLES:: 

 

sage: SL2Z.reduce_cusp(Cusps(-1/4)) 

Infinity 

""" 

return Cusp(1,0) 

 

def random_element(self, bound=100, *args, **kwds): 

r""" 

Return a random element of `{\rm SL}_2(\ZZ)` with entries whose 

absolute value is strictly less than bound (default 100). 

Additional arguments and keywords are passed to the random_element 

method of ZZ. 

 

(Algorithm: Generate a random pair of integers at most bound. If they 

are not coprime, throw them away and start again. If they are, find an 

element of `{\rm SL}_2(\ZZ)` whose bottom row is that, and 

left-multiply it by `\begin{pmatrix} 1 & w \\ 0 & 1\end{pmatrix}` for 

an integer `w` randomly chosen from a small enough range that the 

answer still has entries at most bound.) 

 

It is, unfortunately, not true that all elements of SL2Z with entries < 

bound appear with equal probability; those with larger bottom rows are 

favoured, because there are fewer valid possibilities for w. 

 

EXAMPLES:: 

 

sage: SL2Z.random_element() 

[60 13] 

[83 18] 

sage: SL2Z.random_element(5) 

[-1 3] 

[ 1 -4] 

 

Passes extra positional or keyword arguments through:: 

 

sage: SL2Z.random_element(5, distribution='1/n') 

[ 1 -4] 

[ 0 1] 

""" 

if bound <= 1: raise ValueError("bound must be greater than 1") 

c = ZZ.random_element(1-bound, bound, *args, **kwds) 

d = ZZ.random_element(1-bound, bound, *args, **kwds) 

if gcd(c,d) != 1: # try again 

return self.random_element(bound, *args, **kwds) 

else: 

a,b,c,d = lift_to_sl2z(c,d,0) 

whi = bound 

wlo = bound 

if c > 0: 

whi = min(whi, ((bound - a)/ZZ(c)).ceil()) 

wlo = min(wlo, ((bound + a)/ZZ(c)).ceil()) 

elif c < 0: 

whi = min(whi, ((bound + a)/ZZ(-c)).ceil()) 

wlo = min(wlo, ((bound - a)/ZZ(-c)).ceil()) 

 

if d > 0: 

whi = min(whi, ((bound - b)/ZZ(d)).ceil()) 

wlo = min(wlo, ((bound + b)/ZZ(d)).ceil()) 

elif d < 0: 

whi = min(whi, ((bound + b)/ZZ(-d)).ceil()) 

wlo = min(wlo, ((bound - b)/ZZ(-d)).ceil()) 

 

w = ZZ.random_element(1-wlo, whi, *args, **kwds) 

a += c*w 

b += d*w 

return self([a,b,c,d]) 

 

 

SL2Z = SL2Z_class() 

 

def _SL2Z_ref(): 

""" 

Return SL2Z. (Used for pickling SL2Z.) 

 

EXAMPLES:: 

 

sage: sage.modular.arithgroup.congroup_sl2z._SL2Z_ref() 

Modular Group SL(2,Z) 

sage: sage.modular.arithgroup.congroup_sl2z._SL2Z_ref() is SL2Z 

True 

""" 

return SL2Z