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

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

r""" 

Sets of morphisms between free modules 

 

The class :class:`FreeModuleHomset` implements sets of homomorphisms between 

two free modules of finite rank over the same commutative ring. 

 

AUTHORS: 

 

- Eric Gourgoulhon, Michal Bejger (2014-2015): initial version 

 

REFERENCES: 

 

- Chaps. 13, 14 of R. Godement : *Algebra* [God1968]_ 

- Chap. 3 of S. Lang : *Algebra* [Lan2002]_ 

 

""" 

from __future__ import absolute_import 

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

# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr> 

# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl> 

# 

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

# 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.homset import Homset 

from sage.tensor.modules.free_module_morphism import FiniteRankFreeModuleMorphism 

from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism 

from sage.tensor.modules.free_module_tensor import FreeModuleTensor 

 

class FreeModuleHomset(Homset): 

r""" 

Set of homomorphisms between free modules of finite rank over a 

commutative ring. 

 

Given two free modules `M` and `N` of respective ranks `m` and `n` over a 

commutative ring `R`, the class :class:`FreeModuleHomset` implements the 

set `\mathrm{Hom}(M,N)` of homomorphisms `M\rightarrow N`. 

The set `\mathrm{Hom}(M,N)` is actually a free module of rank `mn` over 

`R`, but this aspect is not taken into account here. 

 

This is a Sage *parent* class, whose *element* class is 

:class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism`. 

 

INPUT: 

 

- ``fmodule1`` -- free module `M` (domain of the homomorphisms), as an 

instance of 

:class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` 

- ``fmodule2`` -- free module `N` (codomain of the homomorphisms), as an 

instance of 

:class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` 

- ``name`` -- (default: ``None``) string; name given to the hom-set; if 

none is provided, Hom(M,N) will be used 

- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the 

hom-set; if none is provided, `\mathrm{Hom}(M,N)` will be used 

 

EXAMPLES: 

 

Set of homomorphisms between two free modules over `\ZZ`:: 

 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: N = FiniteRankFreeModule(ZZ, 2, name='N') 

sage: H = Hom(M,N) ; H 

Set of Morphisms from Rank-3 free module M over the Integer Ring 

to Rank-2 free module N over the Integer Ring 

in Category of finite dimensional modules over Integer Ring 

sage: type(H) 

<class 'sage.tensor.modules.free_module_homset.FreeModuleHomset_with_category_with_equality_by_id'> 

sage: H.category() 

Category of homsets of modules over Integer Ring 

 

Hom-sets are cached:: 

 

sage: H is Hom(M,N) 

True 

 

The LaTeX formatting is:: 

 

sage: latex(H) 

\mathrm{Hom}\left(M,N\right) 

 

As usual, the construction of an element is performed by the ``__call__`` 

method; the argument can be the matrix representing the morphism in the 

default bases of the two modules:: 

 

sage: e = M.basis('e') 

sage: f = N.basis('f') 

sage: phi = H([[-1,2,0], [5,1,2]]) ; phi 

Generic morphism: 

From: Rank-3 free module M over the Integer Ring 

To: Rank-2 free module N over the Integer Ring 

sage: phi.parent() is H 

True 

 

An example of construction from a matrix w.r.t. bases that are not the 

default ones:: 

 

sage: ep = M.basis('ep', latex_symbol=r"e'") 

sage: fp = N.basis('fp', latex_symbol=r"f'") 

sage: phi2 = H([[3,2,1], [1,2,3]], bases=(ep,fp)) ; phi2 

Generic morphism: 

From: Rank-3 free module M over the Integer Ring 

To: Rank-2 free module N over the Integer Ring 

 

The zero element:: 

 

sage: z = H.zero() ; z 

Generic morphism: 

From: Rank-3 free module M over the Integer Ring 

To: Rank-2 free module N over the Integer Ring 

sage: z.matrix(e,f) 

[0 0 0] 

[0 0 0] 

 

The test suite for H is passed:: 

 

sage: TestSuite(H).run() 

 

The set of homomorphisms `M\rightarrow M`, i.e. endomorphisms, is 

obtained by the function ``End``:: 

 

sage: End(M) 

Set of Morphisms from Rank-3 free module M over the Integer Ring 

to Rank-3 free module M over the Integer Ring 

in Category of finite dimensional modules over Integer Ring 

 

``End(M)`` is actually identical to ``Hom(M,M)``:: 

 

sage: End(M) is Hom(M,M) 

True 

 

The unit of the endomorphism ring is the identity map:: 

 

sage: End(M).one() 

Identity endomorphism of Rank-3 free module M over the Integer Ring 

 

whose matrix in any basis is of course the identity matrix:: 

 

sage: End(M).one().matrix(e) 

[1 0 0] 

[0 1 0] 

[0 0 1] 

 

There is a canonical identification between endomorphisms of `M` and 

tensors of type `(1,1)` on `M`. Accordingly, coercion maps have been 

implemented between `\mathrm{End}(M)` and `T^{(1,1)}(M)` (the module of 

all type-`(1,1)` tensors on `M`, see 

:class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule`):: 

 

sage: T11 = M.tensor_module(1,1) ; T11 

Free module of type-(1,1) tensors on the Rank-3 free module M over 

the Integer Ring 

sage: End(M).has_coerce_map_from(T11) 

True 

sage: T11.has_coerce_map_from(End(M)) 

True 

 

See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule` for 

examples of the above coercions. 

 

There is a coercion `\mathrm{GL}(M) \rightarrow \mathrm{End}(M)`, since 

every automorphism is an endomorphism:: 

 

sage: GL = M.general_linear_group() ; GL 

General linear group of the Rank-3 free module M over the Integer Ring 

sage: End(M).has_coerce_map_from(GL) 

True 

 

Of course, there is no coercion in the reverse direction, since only 

bijective endomorphisms are automorphisms:: 

 

sage: GL.has_coerce_map_from(End(M)) 

False 

 

The coercion `\mathrm{GL}(M) \rightarrow \mathrm{End}(M)` in action:: 

 

sage: a = GL.an_element() ; a 

Automorphism of the Rank-3 free module M over the Integer Ring 

sage: a.matrix(e) 

[ 1 0 0] 

[ 0 -1 0] 

[ 0 0 1] 

sage: ea = End(M)(a) ; ea 

Generic endomorphism of Rank-3 free module M over the Integer Ring 

sage: ea.matrix(e) 

[ 1 0 0] 

[ 0 -1 0] 

[ 0 0 1] 

 

""" 

 

Element = FiniteRankFreeModuleMorphism 

 

def __init__(self, fmodule1, fmodule2, name=None, latex_name=None): 

r""" 

TESTS:: 

 

sage: from sage.tensor.modules.free_module_homset import FreeModuleHomset 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: N = FiniteRankFreeModule(ZZ, 2, name='N') 

sage: FreeModuleHomset(M, N) 

Set of Morphisms from Rank-3 free module M over the Integer Ring 

to Rank-2 free module N over the Integer Ring 

in Category of finite dimensional modules over Integer Ring 

 

sage: H = FreeModuleHomset(M, N, name='L(M,N)', 

....: latex_name=r'\mathcal{L}(M,N)') 

sage: latex(H) 

\mathcal{L}(M,N) 

 

""" 

from .finite_rank_free_module import FiniteRankFreeModule 

if not isinstance(fmodule1, FiniteRankFreeModule): 

raise TypeError("fmodule1 = {} is not an ".format(fmodule1) + 

"instance of FiniteRankFreeModule") 

if not isinstance(fmodule2, FiniteRankFreeModule): 

raise TypeError("fmodule2 = {} is not an ".format(fmodule2) + 

"instance of FiniteRankFreeModule") 

if fmodule1.base_ring() != fmodule2.base_ring(): 

raise TypeError("the domain and codomain are not defined over " + 

"the same ring") 

Homset.__init__(self, fmodule1, fmodule2) 

if name is None: 

self._name = "Hom(" + fmodule1._name + "," + fmodule2._name + ")" 

else: 

self._name = name 

if latex_name is None: 

self._latex_name = \ 

r"\mathrm{Hom}\left(" + fmodule1._latex_name + "," + \ 

fmodule2._latex_name + r"\right)" 

else: 

self._latex_name = latex_name 

self._one = None # to be set by self.one() if self is an endomorphism 

# set (fmodule1 = fmodule2) 

 

def _latex_(self): 

r""" 

LaTeX representation of the object. 

 

EXAMPLES:: 

 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: N = FiniteRankFreeModule(ZZ, 2, name='N') 

sage: H = Hom(M,N) 

sage: H._latex_() 

'\\mathrm{Hom}\\left(M,N\\right)' 

sage: latex(H) # indirect doctest 

\mathrm{Hom}\left(M,N\right) 

 

""" 

if self._latex_name is None: 

return r'\mbox{' + str(self) + r'}' 

else: 

return self._latex_name 

 

def __call__(self, *args, **kwds): 

r""" 

To bypass Homset.__call__, enforcing Parent.__call__ instead. 

 

EXAMPLES:: 

 

sage: M = FiniteRankFreeModule(ZZ, 2, name='M') 

sage: N = FiniteRankFreeModule(ZZ, 3, name='N') 

sage: H = Hom(M,N) 

sage: e = M.basis('e') ; f = N.basis('f') 

sage: a = H.__call__(0) ; a 

Generic morphism: 

From: Rank-2 free module M over the Integer Ring 

To: Rank-3 free module N over the Integer Ring 

sage: a.matrix(e,f) 

[0 0] 

[0 0] 

[0 0] 

sage: a == H.zero() 

True 

sage: a == H(0) 

True 

sage: a = H.__call__([[1,2],[3,4],[5,6]], bases=(e,f), name='a') ; a 

Generic morphism: 

From: Rank-2 free module M over the Integer Ring 

To: Rank-3 free module N over the Integer Ring 

sage: a.matrix(e,f) 

[1 2] 

[3 4] 

[5 6] 

sage: a == H([[1,2],[3,4],[5,6]], bases=(e,f)) 

True 

 

""" 

from sage.structure.parent import Parent 

return Parent.__call__(self, *args, **kwds) 

 

#### Methods required for any Parent 

 

def _element_constructor_(self, matrix_rep, bases=None, name=None, 

latex_name=None, is_identity=False): 

r""" 

Construct an element of ``self``, i.e. a homomorphism M --> N, where 

M is the domain of ``self`` and N its codomain. 

 

INPUT: 

 

- ``matrix_rep`` -- matrix representation of the homomorphism with 

respect to the bases ``basis1`` and ``basis2``; this entry can 

actually be any material from which a matrix of size rank(N)*rank(M) 

can be constructed 

- ``bases`` -- (default: ``None``) pair (basis_M, basis_N) defining the 

matrix representation, basis_M being a basis of module `M` and 

basis_N a basis of module `N` ; if none is provided the pair formed 

by the default bases of each module is assumed. 

- ``name`` -- (default: ``None``) string; name given to the 

homomorphism 

- ``latex_name`` -- (default: ``None``)string; LaTeX symbol to denote 

the homomorphism; if none is provided, ``name`` will be used. 

- ``is_identity`` -- (default: ``False``) determines whether the 

constructed object is the identity endomorphism; if set to ``True``, 

then N must be M and the entry ``matrix_rep`` is not used. 

 

EXAMPLES: 

 

Construction of a homomorphism between two free `\ZZ`-modules:: 

 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: N = FiniteRankFreeModule(ZZ, 2, name='N') 

sage: e = M.basis('e') ; f = N.basis('f') 

sage: H = Hom(M,N) 

sage: phi = H._element_constructor_([[2,-1,3], [1,0,-4]], bases=(e,f), 

....: name='phi', latex_name=r'\phi') 

sage: phi 

Generic morphism: 

From: Rank-3 free module M over the Integer Ring 

To: Rank-2 free module N over the Integer Ring 

sage: phi.matrix(e,f) 

[ 2 -1 3] 

[ 1 0 -4] 

sage: phi == H([[2,-1,3], [1,0,-4]], bases=(e,f), name='phi', 

....: latex_name=r'\phi') 

True 

 

Construction of an endomorphism:: 

 

sage: EM = End(M) 

sage: phi = EM._element_constructor_([[1,2,3],[4,5,6],[7,8,9]], 

....: name='phi', latex_name=r'\phi') 

sage: phi 

Generic endomorphism of Rank-3 free module M over the Integer Ring 

sage: phi.matrix(e,e) 

[1 2 3] 

[4 5 6] 

[7 8 9] 

 

Coercion of a type-`(1,1)` tensor to an endomorphism:: 

 

sage: a = M.tensor((1,1)) 

sage: a[:] = [[1,2,3],[4,5,6],[7,8,9]] 

sage: EM = End(M) 

sage: phi_a = EM._element_constructor_(a) ; phi_a 

Generic endomorphism of Rank-3 free module M over the Integer Ring 

sage: phi_a.matrix(e,e) 

[1 2 3] 

[4 5 6] 

[7 8 9] 

sage: phi_a == phi 

True 

sage: phi_a1 = EM(a) ; phi_a1 # indirect doctest 

Generic endomorphism of Rank-3 free module M over the Integer Ring 

sage: phi_a1 == phi 

True 

 

""" 

if isinstance(matrix_rep, FreeModuleTensor): 

# coercion of a type-(1,1) tensor to an endomorphism 

# (this includes automorphisms, since the class 

# FreeModuleAutomorphism inherits from FreeModuleTensor) 

tensor = matrix_rep # for readability 

if tensor.tensor_type() == (1,1) and \ 

self.is_endomorphism_set() and \ 

tensor.base_module() is self.domain(): 

basis = tensor.pick_a_basis() 

tcomp = tensor.comp(basis) 

fmodule = tensor.base_module() 

mat = [[ tcomp[[i,j]] for j in fmodule.irange()] \ 

for i in fmodule.irange()] 

if isinstance(tensor, FreeModuleAutomorphism): 

is_identity = tensor._is_identity 

else: 

is_identity = False 

resu = self.element_class(self, mat, bases=(basis,basis), 

name=tensor._name, latex_name=tensor._latex_name, 

is_identity=is_identity) 

else: 

raise TypeError("cannot coerce the {}".format(tensor) + 

" to an element of {}".format(self)) 

else: 

# Standard construction: 

resu = self.element_class(self, matrix_rep, bases=bases, name=name, 

latex_name=latex_name, 

is_identity=is_identity) 

return resu 

 

def _an_element_(self): 

r""" 

Construct some (unamed) element. 

 

EXAMPLES:: 

 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: N = FiniteRankFreeModule(ZZ, 2, name='N') 

sage: e = M.basis('e') ; f = N.basis('f') 

sage: phi = Hom(M,N)._an_element_() ; phi 

Generic morphism: 

From: Rank-3 free module M over the Integer Ring 

To: Rank-2 free module N over the Integer Ring 

sage: phi.matrix(e,f) 

[1 1 1] 

[1 1 1] 

sage: phi == Hom(M,N).an_element() 

True 

 

""" 

ring = self.base_ring() 

m = self.domain().rank() 

n = self.codomain().rank() 

matrix_rep = [[ring.an_element() for i in range(m)] for j in range(n)] 

return self.element_class(self, matrix_rep) 

 

def _coerce_map_from_(self, other): 

r""" 

Determine whether coercion to self exists from other parent. 

 

EXAMPLES: 

 

The module of type-`(1,1)` tensors coerces to ``self``, if the latter 

is some endomorphism set:: 

 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: e = M.basis('e') 

sage: End(M)._coerce_map_from_(M.tensor_module(1,1)) 

True 

sage: End(M).has_coerce_map_from(M.tensor_module(1,1)) 

True 

sage: End(M)._coerce_map_from_(M.tensor_module(1,2)) 

False 

 

The general linear group coerces to the endomorphism ring:: 

 

sage: End(M)._coerce_map_from_(M.general_linear_group()) 

True 

 

""" 

from sage.tensor.modules.tensor_free_module import TensorFreeModule 

from sage.tensor.modules.free_module_linear_group import \ 

FreeModuleLinearGroup 

if isinstance(other, TensorFreeModule): 

# Coercion of a type-(1,1) tensor to an endomorphism: 

if other.tensor_type() == (1,1): 

return self.is_endomorphism_set() and \ 

other.base_module() is self.domain() 

if isinstance(other, FreeModuleLinearGroup): 

# Coercion of an automorphism to an endomorphism: 

return self.is_endomorphism_set() and \ 

other.base_module() is self.domain() 

return False 

 

#### End of methods required for any Parent 

 

 

#### Monoid methods (case of an endomorphism set) #### 

 

def one(self): 

r""" 

Return the identity element of ``self`` considered as a monoid (case of 

an endomorphism set). 

 

This applies only when the codomain of ``self`` is equal to its domain, 

i.e. when ``self`` is of the type `\mathrm{Hom}(M,M)`. 

 

OUTPUT: 

 

- the identity element of `\mathrm{End}(M) = \mathrm{Hom}(M,M)`, as an 

instance of 

:class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism` 

 

EXAMPLES: 

 

Identity element of the set of endomorphisms of a free module 

over `\ZZ`:: 

 

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') 

sage: e = M.basis('e') 

sage: H = End(M) 

sage: H.one() 

Identity endomorphism of Rank-3 free module M over the Integer Ring 

sage: H.one().matrix(e) 

[1 0 0] 

[0 1 0] 

[0 0 1] 

sage: H.one().is_identity() 

True 

 

NB: mathematically, ``H.one()`` coincides with the identity map of the 

free module `M`. However the latter is considered here as an 

element of `\mathrm{GL}(M)`, the general linear group of `M`. 

Accordingly, one has to use the coercion map 

`\mathrm{GL}(M) \rightarrow \mathrm{End}(M)` 

to recover ``H.one()`` from ``M.identity_map()``:: 

 

sage: M.identity_map() 

Identity map of the Rank-3 free module M over the Integer Ring 

sage: M.identity_map().parent() 

General linear group of the Rank-3 free module M over the Integer Ring 

sage: H.one().parent() 

Set of Morphisms from Rank-3 free module M over the Integer Ring 

to Rank-3 free module M over the Integer Ring 

in Category of finite dimensional modules over Integer Ring 

sage: H.one() == H(M.identity_map()) 

True 

 

Conversely, one can recover ``M.identity_map()`` from ``H.one()`` by 

means of a conversion `\mathrm{End}(M)\rightarrow \mathrm{GL}(M)`:: 

 

sage: GL = M.general_linear_group() 

sage: M.identity_map() == GL(H.one()) 

True 

 

""" 

if self._one is None: 

if self.codomain() != self.domain(): 

raise TypeError("the {} is not a monoid".format(self)) 

self._one = self.element_class(self, [], is_identity=True) 

return self._one 

 

#### End of monoid methods ####