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

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

r""" 

Semidirect product of groups 

 

AUTHORS: 

 

- Mark Shimozono (2013) initial version 

""" 

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

# Copyright (C) 2013 Mark Shimozono <mshimo at math.vt.edu> 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 2 of the License, or 

# (at your option) any later version. 

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

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

from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups 

from sage.categories.groups import Groups 

from sage.sets.cartesian_product import CartesianProduct 

from sage.misc.cachefunc import cached_method 

 

class GroupSemidirectProductElement(CartesianProduct.Element): 

r""" 

Element class for :class:`GroupSemidirectProduct`. 

""" 

 

def _repr_(self): 

r""" 

A string representing the semidirect product group. 

 

EXAMPLES:: 

 

sage: def twist(x,y): 

....: return y 

sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist) # indirect doctest 

Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) acting on Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) 

""" 

 

def wrapper(prefix, s): 

if prefix is None: 

return s 

return "%s[%s]"%(prefix,s) 

 

par = self.parent() 

 

g = self.cartesian_projection(0) 

h = self.cartesian_projection(1) 

gstr = wrapper(par._prefix0, repr(g)) 

hstr = wrapper(par._prefix1, repr(h)) 

if par._print_tuple: 

return "(%s, %s)"%(gstr,hstr) 

 

if self == par.one(): 

return "1" 

if g == g.parent().one(): 

return hstr 

if h == h.parent().one(): 

return gstr 

return gstr + " * " + hstr 

 

def inverse(self): 

r""" 

The inverse of ``self``. 

 

EXAMPLES:: 

 

sage: L = RootSystem(['A',2]).root_lattice() 

sage: from sage.groups.group_exp import GroupExp 

sage: EL = GroupExp()(L) 

sage: W = L.weyl_group(prefix="s") 

sage: def twist(w,v): 

....: return EL(w.action(v.value)) 

sage: G = GroupSemidirectProduct(W, EL, twist, prefix1='t') 

sage: g = G.an_element(); g 

s1*s2 * t[2*alpha[1] + 2*alpha[2]] 

sage: g.inverse() 

s2*s1 * t[2*alpha[1]] 

 

""" 

par = self.parent() 

g = self.cartesian_projection(0) 

h = self.cartesian_projection(1) 

 

if par.act_to_right(): 

return self.__class__(par,(~g, par._twist(g,~h))) 

else: 

hi = ~h 

return self.__class__(par,(par._twist(hi,~g),hi)) 

 

__invert__ = inverse 

 

def to_opposite(self): 

r""" 

Send an element to its image in the opposite semidirect product. 

 

EXAMPLES:: 

 

sage: L = RootSystem(['A',2]).root_lattice(); L 

Root lattice of the Root system of type ['A', 2] 

sage: from sage.groups.group_exp import GroupExp 

sage: EL = GroupExp()(L) 

sage: W = L.weyl_group(prefix="s"); W 

Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice) 

sage: def twist(w,v): 

....: return EL(w.action(v.value)) 

sage: G = GroupSemidirectProduct(W, EL, twist, prefix1='t'); G 

Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice) acting on Multiplicative form of Root lattice of the Root system of type ['A', 2] 

sage: mu = L.an_element(); mu 

2*alpha[1] + 2*alpha[2] 

sage: w = W.an_element(); w 

s1*s2 

sage: g = G((w,EL(mu))); g 

s1*s2 * t[2*alpha[1] + 2*alpha[2]] 

sage: g.to_opposite() 

t[-2*alpha[1]] * s1*s2 

sage: g.to_opposite().parent() 

Semidirect product of Multiplicative form of Root lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice) 

""" 

par = self.parent() 

Gop = par.opposite_semidirect_product() 

g = self.cartesian_projection(0) 

h = self.cartesian_projection(1) 

if par.act_to_right(): 

return Gop((par._twist(g,h),g)) 

return Gop((h,par._twist(~h,g))) 

 

 

class GroupSemidirectProduct(CartesianProduct): 

r""" 

Return the semidirect product of the groups ``G`` and ``H`` using the homomorphism ``twist``. 

 

INPUT: 

 

- ``G`` and ``H`` -- multiplicative groups 

- ``twist`` -- (default: None) a function defining a homomorphism (see below) 

- ``act_to_right`` -- True or False (default: True) 

- ``prefix0`` -- (default: None) optional string 

- ``prefix1`` -- (default: None) optional string 

- ``print_tuple`` -- True or False (default: False) 

- ``category`` -- A category (default: Groups()) 

 

A semidirect product of groups `G` and `H` is a group structure on the Cartesian product `G \times H` 

whose product agrees with that of `G` on `G \times 1_H` and with that of `H` on `1_G \times H`, such that 

either `1_G \times H` or `G \times 1_H` is a normal subgroup. In the former case the group is denoted 

`G \ltimes H` and in the latter, `G \rtimes H`. 

 

If ``act_to_right`` is True, this indicates the group `G \ltimes H` in which `G` acts on `H` by 

automorphisms. In this case there is a 

group homomorphism `\phi \in \mathrm{Hom}(G, \mathrm{Aut}(H))` such that 

 

.. MATH:: 

 

g h g^{-1} = \phi(g)(h). 

 

The homomorphism `\phi` is specified by the input ``twist``, which syntactically is the function `G\times H\to H` 

defined by 

 

.. MATH:: 

 

twist(g,h) = \phi(g)(h). 

 

The product on `G \ltimes H` is defined by 

 

.. MATH:: 

 

\begin{aligned} 

(g_1,h_1)(g_2,h_2) &= g_1 h_1 g_2 h_2 \\ 

&= g_1 g_2 g_2^{-1} h_1 g_2 h_2 \\ 

&= (g_1g_2, twist(g_2^{-1}, h_1) h_2) 

\end{aligned} 

 

If ``act_to_right`` is False, the group `G \rtimes H` is specified by a homomorphism `\psi\in \mathrm{Hom}(H,\mathrm{Aut}(G))` 

such that 

 

.. MATH:: 

 

h g h^{-1} = \psi(h)(g) 

 

Then ``twist`` is the function `H\times G\to G` defined by 

 

.. MATH:: 

 

twist(h,g) = \psi(h)(g). 

 

so that the product in `G \rtimes H` is defined by 

 

.. MATH:: 

 

\begin{aligned} 

(g_1,h_1)(g_2,h_2) &= g_1 h_1 g_2 h_2 \\ 

&= g_1 h_1 g_2 h_1^{-1} h_1 h_2 \\ 

&= (g_1 twist(h_1,g_2), h_1 h_2) 

\end{aligned} 

 

If ``prefix0`` (resp. ``prefixl``) is not None then it is used as a wrapper for 

printing elements of ``G`` (resp. ``H``). If ``print_tuple`` is True then elements are printed 

in the style `(g,h)` and otherwise in the style `g * h`. 

 

EXAMPLES:: 

 

sage: G = GL(2,QQ) 

sage: V = QQ^2 

sage: EV = GroupExp()(V) # make a multiplicative version of V 

sage: def twist(g,v): 

....: return EV(g*v.value) 

sage: H = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't'); H 

Semidirect product of General Linear Group of degree 2 over Rational Field acting on Multiplicative form of Vector space of dimension 2 over Rational Field 

sage: x = H.an_element(); x 

t[(1, 0)] 

sage: x^2 

t[(2, 0)] 

sage: cartan_type = CartanType(['A',2]) 

sage: W = WeylGroup(cartan_type, prefix="s") 

sage: def twist(w,v): 

....: return w*v*(~w) 

sage: WW = GroupSemidirectProduct(W,W, twist=twist, print_tuple=True) 

sage: s = Family(cartan_type.index_set(), lambda i: W.simple_reflection(i)) 

sage: y = WW((s[1],s[2])); y 

(s1, s2) 

sage: y^2 

(1, s2*s1) 

sage: y.inverse() 

(s1, s1*s2*s1) 

 

.. TODO:: 

 

- Functorial constructor for semidirect products for various categories 

- Twofold Direct product as a special case of semidirect product 

""" 

 

def __init__(self, G, H, twist = None, act_to_right = True, prefix0 = None, prefix1 = None, print_tuple = False, category = Groups()): 

r""" 

 

EXAMPLES:: 

 

sage: def twist(x,y): 

....: return y 

sage: import __main__ 

sage: __main__.twist = twist 

sage: G = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist) 

sage: TestSuite(G).run() 

 

The ``__main__`` business is a trick to pass the picking test. 

 

""" 

 

self._act_to_right = act_to_right 

def check_implemented_group(x): 

if x in Groups(): 

return 

error = "The semidirect product construction for groups is implemented only for multiplicative groups" 

if x in CommutativeAdditiveGroups(): 

error = error + ". Please change the commutative additive group %s into a multiplicative group using the functor sage.groups.group_exp.GroupExp"%x 

raise TypeError(error) 

 

check_implemented_group(G) 

check_implemented_group(H) 

 

if twist is None: 

self._twist = lambda g, h: h # use the trivial twist 

else: 

self._twist = twist 

 

self._prefix0 = prefix0 

self._prefix1 = prefix1 

self._print_tuple = print_tuple 

self._category = category 

CartesianProduct.__init__(self, (G, H), category=category) 

 

def act_to_right(self): 

r""" 

True if the left factor acts on the right factor and 

False if the right factor acts on the left factor. 

 

EXAMPLES:: 

 

sage: def twist(x,y): 

....: return y 

sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist).act_to_right() 

True 

 

""" 

return self._act_to_right 

 

def _repr_(self): 

r""" 

A string representing the semidirect product group. 

 

EXAMPLES:: 

 

sage: def twist(x,y): 

....: return y 

sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist) # indirect doctest 

Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) acting on Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) 

""" 

cartesian_factors = self.cartesian_factors() 

if self.act_to_right(): 

act_string = "acting on" 

else: 

act_string = "acted upon by" 

return "Semidirect product of %s %s %s" % (cartesian_factors[0], act_string, cartesian_factors[1]) 

 

def _element_constructor_(self, x): 

r""" 

EXAMPLES:: 

 

sage: def twist(x,y): 

....: return y 

sage: import __main__ 

sage: __main__.twist = twist 

sage: g = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist).an_element() 

sage: TestSuite(g).run() 

 

""" 

def type_error(): 

raise TypeError("%s cannot be converted into an element of %s" % (x, self)) 

 

if isinstance(x, self.element_class) and x.parent() == self: 

return x 

if not isinstance(x, GroupSemidirectProductElement): 

if not isinstance(x, tuple): 

type_error() 

if len(x) != 2: 

type_error() 

g, h = x 

else: 

g = x.cartesian_projection(0) 

h = x.cartesian_projection(1) 

gg = self.cartesian_factors()[0](g) 

hh = self.cartesian_factors()[1](h) 

# return self._cartesian_product_of_elements((gg,hh)) 

return self.element_class(self,(gg,hh)) 

 

@cached_method 

def one(self): 

r""" 

The identity element of the semidirect product group. 

 

EXAMPLES:: 

 

sage: G = GL(2,QQ) 

sage: V = QQ^2 

sage: EV = GroupExp()(V) # make a multiplicative version of V 

sage: def twist(g,v): 

....: return EV(g*v.value) 

sage: one = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't').one(); one 

1 

sage: one.cartesian_projection(0) 

[1 0] 

[0 1] 

sage: one.cartesian_projection(1) 

(0, 0) 

 

""" 

return self((self.cartesian_factors()[0].one(), self.cartesian_factors()[1].one())) 

 

def group_generators(self): 

r""" 

Return generators of ``self``. 

 

EXAMPLES:: 

 

sage: twist = lambda x,y: y 

sage: import __main__ 

sage: __main__.twist = twist 

sage: EZ = GroupExp()(ZZ) 

sage: GroupSemidirectProduct(EZ,EZ,twist,print_tuple=True).group_generators() 

((1, 0), (0, 1)) 

 

""" 

def has_gens(G): 

if not hasattr(G, 'group_generators'): 

return False 

return G.group_generators() 

 

factors = self.cartesian_factors() 

g0 = has_gens(factors[0]) 

if g0 is not False: 

g1 = has_gens(factors[1]) 

if g1 is not False: 

return tuple([self((x,factors[1].one())) for x in g0] + [self((factors[0].one(),x)) for x in g1]) 

raise NotImplementedError("One of the factors does not implement 'group_generators'") 

 

def product(self, x, y): 

r""" 

The product of elements `x` and `y` in the semidirect product group. 

 

EXAMPLES:: 

 

sage: G = GL(2,QQ) 

sage: V = QQ^2 

sage: EV = GroupExp()(V) # make a multiplicative version of V 

sage: def twist(g,v): 

....: return EV(g*v.value) 

sage: S = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't') 

sage: g = G([[2,1],[3,1]]); g 

[2 1] 

[3 1] 

sage: v = EV.an_element(); v 

(1, 0) 

sage: x = S((g,v)); x 

[2 1] 

[3 1] * t[(1, 0)] 

sage: x*x # indirect doctest 

[7 3] 

[9 4] * t[(0, 3)] 

""" 

xg = x.cartesian_projection(0) 

xh = x.cartesian_projection(1) 

yg = y.cartesian_projection(0) 

yh = y.cartesian_projection(1) 

if self.act_to_right(): 

g = xg * yg 

h = self._twist(~yg,xh) * yh 

else: 

h = xh * yh 

g = xg * self._twist(xh,yg) 

return self((g,h)) 

 

@cached_method 

def opposite_semidirect_product(self): 

r""" 

Create the same semidirect product but with the positions of the groups exchanged. 

 

EXAMPLES:: 

 

sage: G = GL(2,QQ) 

sage: L = QQ^2 

sage: EL = GroupExp()(L) 

sage: H = GroupSemidirectProduct(G, EL, twist = lambda g,v: EL(g*v.value), prefix1 = 't'); H 

Semidirect product of General Linear Group of degree 2 over Rational Field acting on Multiplicative form of Vector space of dimension 2 over Rational Field 

sage: h = H((Matrix([[0,1],[1,0]]), EL.an_element())); h 

[0 1] 

[1 0] * t[(1, 0)] 

sage: Hop = H.opposite_semidirect_product(); Hop 

Semidirect product of Multiplicative form of Vector space of dimension 2 over Rational Field acted upon by General Linear Group of degree 2 over Rational Field 

sage: hop = h.to_opposite(); hop 

t[(0, 1)] * [0 1] 

[1 0] 

sage: hop in Hop 

True 

 

""" 

return GroupSemidirectProduct(self.cartesian_factors()[1], self.cartesian_factors()[0], twist=self._twist, act_to_right = not self.act_to_right(), prefix0 = self._prefix1, prefix1 = self._prefix0, print_tuple = self._print_tuple, category=self._category) 

 

GroupSemidirectProduct.Element = GroupSemidirectProductElement