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

r""" 

Helper classes for structural embeddings and isomorphisms of number fields 

 

AUTHORS: 

 

- Julian Rueth (2014-04-03): initial version 

 

Consider the following fields `L` and `M`:: 

 

sage: L.<a> = QuadraticField(2) 

sage: M.<a> = L.absolute_field() 

 

Both produce the same extension of `\QQ`. However, they should not be 

identical because `M` carries additional information:: 

 

sage: L.structure() 

(Identity endomorphism of Number Field in a with defining polynomial x^2 - 2, 

Identity endomorphism of Number Field in a with defining polynomial x^2 - 2) 

sage: M.structure() 

(Isomorphism given by variable name change map: 

From: Number Field in a with defining polynomial x^2 - 2 

To: Number Field in a with defining polynomial x^2 - 2, 

Isomorphism given by variable name change map: 

From: Number Field in a with defining polynomial x^2 - 2 

To: Number Field in a with defining polynomial x^2 - 2) 

 

This used to cause trouble with caching and made (absolute) number fields not 

unique when they should have been. The underlying technical problem is that the 

morphisms returned by ``structure()`` can only be defined once the fields in 

question have been created. Therefore, these morphisms cannot be part of a key 

which uniquely identifies a number field. 

 

The classes defined in this file encapsulate information about these structure 

morphisms which can be passed to the factory creating number fields. This makes 

it possible to distinguish number fields which only differ in terms of these 

structure morphisms:: 

 

sage: L is M 

False 

sage: N.<a> = L.absolute_field() 

sage: M is N 

True 

 

""" 

from __future__ import absolute_import 

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

# Copyright (C) 2014 Julian Rueth <julian.rueth@fsfe.org> 

# 

# 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.structure.unique_representation import UniqueRepresentation 

 

class NumberFieldStructure(UniqueRepresentation): 

r""" 

Abstract base class encapsulating information about a number fields 

relation to other number fields. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import NumberFieldStructure 

sage: NumberFieldStructure(QQ) 

<sage.rings.number_field.structure.NumberFieldStructure object at 0x...> 

 

Instances are cached through 

:class:`sage.structure.unique_representation.UniqueRepresentation`:: 

 

sage: NumberFieldStructure(QQ) is NumberFieldStructure(QQ) 

True 

 

sage: R.<x> = QQ[] 

sage: K.<i> = NumberField(x^2+1) 

sage: L = K.change_names('j').change_names('i') 

sage: K is L # K and L differ in "structure", one is the "name-change" of the other 

False 

sage: NumberFieldStructure(L) is NumberFieldStructure(L) 

True 

sage: NumberFieldStructure(K) is NumberFieldStructure(L) 

False 

sage: from sage.rings.number_field.structure import NameChange 

sage: KK.<j> = NumberField(x^2+1, structure=NameChange(K)) 

sage: LL.<j> = NumberField(x^2+1, structure=NameChange(L)) 

sage: KK is LL 

False 

 

""" 

def __init__(self, other): 

""" 

Initialization. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import NumberFieldStructure 

sage: type(NumberFieldStructure(QQ)) 

<class 'sage.rings.number_field.structure.NumberFieldStructure'> 

 

""" 

self.other = other 

 

def create_structure(self, field): 

r""" 

Return a tuple encoding structural information about ``field``. 

 

OUTPUT: 

 

Typically, the output is a pair of morphisms. The first one from 

``field`` to a field from which ``field`` has been constructed and the 

second one its inverse. In this case, these morphisms are used as 

conversion maps between the two fields. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import NumberFieldStructure 

sage: NumberFieldStructure(QQ).create_structure(QQ) 

Traceback (most recent call last): 

... 

NotImplementedError 

 

The morphisms created by this method are used as conversion maps:: 

 

sage: K.<i> = QuadraticField(-1) 

sage: L.<j> = K.change_names() 

sage: isinstance(L._structure, NumberFieldStructure) 

True 

sage: from_L, to_L = L.structure() 

sage: L._convert_map_from_(K) is to_L 

True 

sage: L(i) 

j 

sage: K(j) 

i 

 

""" 

raise NotImplementedError 

 

class NameChange(NumberFieldStructure): 

r""" 

Structure for a number field created by a change in variable name. 

 

INPUT: 

 

- ``other`` -- the number field from which this field has been created. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import NameChange 

sage: K.<i> = QuadraticField(-1) 

sage: NameChange(K) 

<sage.rings.number_field.structure.NameChange object at 0x...> 

 

""" 

def create_structure(self, field): 

r""" 

Return a pair of isomorphisms which send the generator of ``field`` to 

the generator of ``other`` and vice versa. 

 

TESTS:: 

 

sage: CyclotomicField(5).absolute_field('a').structure() # indirect doctest 

(Isomorphism given by variable name change map: 

From: Number Field in a with defining polynomial x^4 + x^3 + x^2 + x + 1 

To: Cyclotomic Field of order 5 and degree 4, 

Isomorphism given by variable name change map: 

From: Cyclotomic Field of order 5 and degree 4 

To: Number Field in a with defining polynomial x^4 + x^3 + x^2 + x + 1) 

 

""" 

from . import maps 

return maps.NameChangeMap(field, self.other), maps.NameChangeMap(self.other, field) 

 

class AbsoluteFromRelative(NumberFieldStructure): 

r""" 

Structure for an absolute number field created from a relative number 

field. 

 

INPUT: 

 

- ``other`` -- the number field from which this field has been created. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import AbsoluteFromRelative 

sage: K.<a> = QuadraticField(2) 

sage: R.<x> = K[] 

sage: L.<b> = K.extension(x^2 - 3) 

sage: AbsoluteFromRelative(L) 

<sage.rings.number_field.structure.AbsoluteFromRelative object at 0x...> 

 

""" 

def create_structure(self, field): 

r""" 

Return a pair of isomorphisms which go from ``field`` to ``other`` and 

vice versa. 

 

TESTS:: 

 

sage: K.<a> = QuadraticField(2) 

sage: R.<x> = K[] 

sage: L.<b> = K.extension(x^2 - 3) 

sage: M.<c> = L.absolute_field() 

sage: M.structure() # indirect doctest 

(Isomorphism map: 

From: Number Field in c with defining polynomial x^4 - 10*x^2 + 1 

To: Number Field in b with defining polynomial x^2 - 3 over its base field, Isomorphism map: 

From: Number Field in b with defining polynomial x^2 - 3 over its base field 

To: Number Field in c with defining polynomial x^4 - 10*x^2 + 1) 

 

""" 

from . import maps 

return maps.MapAbsoluteToRelativeNumberField(field, self.other), maps.MapRelativeToAbsoluteNumberField(self.other, field) 

 

class RelativeFromAbsolute(NumberFieldStructure): 

r""" 

Structure for a relative number field created from an absolute number 

field. 

 

INPUT: 

 

- ``other`` -- the (absolute) number field from which this field has been 

created. 

 

- ``gen`` -- the generator of the intermediate field 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import RelativeFromAbsolute 

sage: RelativeFromAbsolute(QQ, 1/2) 

<sage.rings.number_field.structure.RelativeFromAbsolute object at 0x...> 

 

""" 

def __init__(self, other, gen): 

r""" 

Initialization. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import RelativeFromAbsolute 

sage: type(RelativeFromAbsolute(QQ, 1/2)) 

<class 'sage.rings.number_field.structure.RelativeFromAbsolute'> 

 

""" 

NumberFieldStructure.__init__(self, other) 

self.gen = gen 

 

def create_structure(self, field): 

r""" 

Return a pair of isomorphisms which go from ``field`` to ``other`` and 

vice versa. 

 

INPUT: 

 

- ``field`` -- a relative number field 

 

TESTS:: 

 

sage: K.<a> = QuadraticField(2) 

sage: M.<b,a_> = K.relativize(-a) 

sage: M.structure() # indirect doctest 

(Relative number field morphism: 

From: Number Field in b with defining polynomial x + a_ over its base field 

To: Number Field in a with defining polynomial x^2 - 2 

Defn: -a_ |--> a 

a_ |--> -a, Ring morphism: 

From: Number Field in a with defining polynomial x^2 - 2 

To: Number Field in b with defining polynomial x + a_ over its base field 

Defn: a |--> -a_) 

 

""" 

# other field 

# \ / 

# \ Q(gen) 

# \ / 

# Q 

other = self.other 

gen = self.gen 

 

# the isomorphism from left to right is easy since the generators of 

# other and field are the same 

other_to_field = other.hom([field.gen(0)], field, check=True) 

assert other_to_field(gen) == field(field.base_field().gen()) 

 

# to go from right to left, we first define a map from Q(gen) to other 

base_hom = field.base_field().hom([gen], other) 

# and extend it to a map from field 

field_to_other = field.Hom(other)([other.gen()], base_hom=base_hom, check=True) 

 

return field_to_other, other_to_field 

 

class RelativeFromRelative(NumberFieldStructure): 

r""" 

Structure for a relative number field created from another relative number 

field. 

 

INPUT: 

 

- ``other`` -- the relative number field used in the construction, see 

:meth:`create_structure`; there this field will be called ``field_``. 

 

TESTS:: 

 

sage: from sage.rings.number_field.structure import RelativeFromRelative 

sage: K.<i> = QuadraticField(-1) 

sage: R.<x> = K[] 

sage: L.<a> = K.extension(x^2 - 2) 

sage: RelativeFromRelative(L) 

<sage.rings.number_field.structure.RelativeFromRelative object at 0x...> 

 

""" 

def create_structure(self, field): 

r""" 

Return a pair of isomorphisms which go from ``field`` to the relative 

number field (called ``other`` below) from which ``field`` has been 

created and vice versa. 

 

The isomorphism is created via the relative number field ``field_`` 

which is identical to ``field`` but is equipped with an isomorphism to 

an absolute field which was used in the construction of ``field``. 

 

INPUT: 

 

- ``field`` -- a relative number field 

 

TESTS:: 

 

sage: K.<i> = QuadraticField(-1) 

sage: R.<x> = K[] 

sage: L.<a> = K.extension(x^2 - 2) 

sage: M.<b,a> = L.relativize(a) 

sage: M.structure() # indirect doctest 

(Relative number field morphism: 

From: Number Field in b with defining polynomial x^2 - 2*a*x + 3 over its base field 

To: Number Field in a with defining polynomial x^2 - 2 over its base field 

Defn: b |--> a - i 

a |--> a, Relative number field morphism: 

From: Number Field in a with defining polynomial x^2 - 2 over its base field 

To: Number Field in b with defining polynomial x^2 - 2*a*x + 3 over its base field 

Defn: a |--> a 

i |--> -b + a) 

 

""" 

# other and field_ are relative number fields which are isomorphic via 

# an absolute number field abs. 

# field and field_ are identical except that field_.structure() returns 

# the isomorphism with abs and field returns an isomorphism with other 

# (which we construct in this method). 

# 

# f g h 

# other -> abs -> field_ -> field 

field_ = self.other 

g_, g = field_.structure() 

abs = g.domain() 

f_, f = abs.structure() 

other = f.domain() 

h = lambda x: field._element_constructor_(x.list()) 

h_ = lambda x: field_._element_constructor_(x.list()) 

 

# First, we construct the isomorphism from other to field by embedding 

# other.base_field() into field. 

gf = g*f 

base = other.base_field() 

base_to_field = base.Hom(field)([h(gf(other.gen(1)))]) 

other_to_field = other.Hom(field)([h(gf(other.gen()))], base_hom=base_to_field) 

 

# And its inverse, essentially the same construction: 

f_g_ = f_*g_ 

base = field.base_field() 

base_to_other = base.Hom(other)([f_g_(h_(field.gen(1)))]) 

field_to_other = field.Hom(other)([f_g_(h_(field.gen()))], base_hom=base_to_other) 

 

return field_to_other, other_to_field