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

r""" 

Base class for old-style parent objects 

  

CLASS HIERARCHY: 

  

SageObject 

Parent 

ParentWithBase 

ParentWithGens 

  

  

TESTS: 

  

This came up in some subtle bug once. 

:: 

  

sage: gp(2) + gap(3) 

5 

""" 

  

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

# Copyright (C) 2006 William Stein <wstein@gmail.com> 

# 

# 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 __future__ import absolute_import, print_function 

  

cimport sage.structure.sage_object as sage_object 

import operator 

from .parent import Set_PythonType, Set_PythonType_class 

from .coerce cimport py_scalar_parent 

from sage.ext.stdsage cimport HAS_DICTIONARY 

  

from cpython.object cimport * 

from cpython.bool cimport * 

  

cdef inline check_old_coerce(Parent p): 

if p._element_constructor is not None: 

raise RuntimeError("%s still using old coercion framework" % p) 

  

  

cdef class Parent(parent.Parent): 

""" 

Parents are the SAGE/mathematical analogues of container objects 

in computer science. 

  

TESTS:: 

  

sage: V = VectorSpace(GF(2,'a'),2) 

sage: V.list() 

[(0, 0), (1, 0), (0, 1), (1, 1)] 

sage: MatrixSpace(GF(3), 1, 1).list() 

[[0], [1], [2]] 

sage: DirichletGroup(3).list() 

[Dirichlet character modulo 3 of conductor 1 mapping 2 |--> 1, 

Dirichlet character modulo 3 of conductor 3 mapping 2 |--> -1] 

sage: K = GF(7^6,'a') 

sage: K.list()[:10] # long time 

[0, 1, 2, 3, 4, 5, 6, a, a + 1, a + 2] 

sage: K.<a> = GF(4) 

sage: K.list() 

[0, a, a + 1, 1] 

""" 

  

def __init__(self, coerce_from=None, actions=None, embeddings=None, *, category=None): 

self.init_coerce(False) 

if coerce_from is not None: 

from sage.misc.superseded import deprecation 

deprecation(24614, "the 'coerce_from' keyword is deprecated") 

self._coerce_from_list = list(coerce_from) 

self._coerce_from_hash = MonoDict() 

if actions is not None: 

from sage.misc.superseded import deprecation 

deprecation(24614, "the 'actions' keyword is deprecated") 

self._action_list = list(actions) 

self._action_hash = TripleDict() 

  

cdef parent.Parent other 

if embeddings is not None: 

from sage.misc.superseded import deprecation 

deprecation(24614, "the 'embeddings' keyword is deprecated") 

for mor in embeddings: 

other = mor.domain() 

print("embedding", self, " --> ", other) 

print(mor) 

other.init_coerce() # TODO remove when we can 

other._coerce_from_list.append(mor) 

  

self._set_element_constructor() 

  

# old 

self._has_coerce_map_from = MonoDict() 

if category is not None: 

self._init_category_(category) 

  

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

# New Coercion support functionality 

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

  

cpdef coerce_map_from_c(self, S): 

""" 

EXAMPLES: 

  

Check to make sure that we handle coerce maps from Python 

native types correctly:: 

  

sage: QQ['q,t'].coerce_map_from(int) 

Composite map: 

From: Set of Python objects of class 'int' 

To: Multivariate Polynomial Ring in q, t over Rational Field 

Defn: Native morphism: 

From: Set of Python objects of class 'int' 

To: Rational Field 

then 

Polynomial base injection morphism: 

From: Rational Field 

To: Multivariate Polynomial Ring in q, t over Rational Field 

""" 

check_old_coerce(self) 

if S is self: 

from sage.categories.homset import Hom 

return Hom(self, self).identity() 

elif S == self: 

# non-unique parents 

from sage.categories.homset import Hom 

from sage.categories.morphism import CallMorphism 

return CallMorphism(Hom(S, self)) 

elif isinstance(S, Set_PythonType_class): 

return self.coerce_map_from_c(S._type) 

if self._coerce_from_hash is None: # this is because parent.__init__() does not always get called 

self.init_coerce() 

cdef object ret 

try: 

ret = self._coerce_from_hash.get(S) 

return ret 

except KeyError: 

pass 

  

mor = self.coerce_map_from_c_impl(S) 

import sage.categories.morphism 

import sage.categories.map 

if mor is True: 

mor = sage.categories.morphism.CallMorphism(S, self) 

elif mor is False: 

mor = None 

elif mor is not None and not isinstance(mor, sage.categories.map.Map): 

raise TypeError("coerce_map_from_c_impl must return a boolean, None, or an explicit Map") 

  

if mor is None and isinstance(S, type): 

#Convert Python types to native Sage types 

sage_type = py_scalar_parent(S) 

if sage_type is None: 

self._coerce_from_hash[S] = None 

return None 

mor = self.coerce_map_from_c(sage_type) 

if mor is not None: 

mor = mor * sage_type._internal_coerce_map_from(S) 

  

if mor is not None: 

self._coerce_from_hash.set(S, mor) # TODO: if this is None, could it be non-None in the future? 

  

return mor 

  

cdef coerce_map_from_c_impl(self, S): 

check_old_coerce(self) 

import sage.categories.morphism 

from sage.categories.map import Map 

from sage.categories.homset import Hom 

cdef parent.Parent R 

for mor in self._coerce_from_list: 

if isinstance(mor, Map): 

R = mor.domain() 

else: 

R = mor 

mor = sage.categories.morphism.CallMorphism(Hom(R, self)) 

i = self._coerce_from_list.index(R) 

self._coerce_from_list[i] = mor # cache in case we need it again 

if R is S: 

return mor 

else: 

connecting = R._internal_coerce_map_from(S) 

if connecting is not None: 

return mor * connecting 

  

# Piggyback off the old code for now 

# WARNING: when working on this, make sure circular dependencies aren't introduced! 

if self.has_coerce_map_from_c(S): 

if isinstance(S, type): 

S = Set_PythonType(S) 

return sage.categories.morphism.CallMorphism(Hom(S, self)) 

else: 

return None 

  

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

# Coercion support functionality 

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

  

def _coerce_(self, x): # Call this from Python (do not override!) 

if self._element_constructor is not None: 

return self.coerce(x) 

check_old_coerce(self) 

return self._coerce_c(x) 

  

cpdef _coerce_c(self, x): # DO NOT OVERRIDE THIS (call it) 

if self._element_constructor is not None: 

return self.coerce(x) 

check_old_coerce(self) 

try: 

P = x.parent() # todo -- optimize 

if P is self: 

return x 

except AttributeError as msg: 

pass 

if HAS_DICTIONARY(self): 

return self._coerce_impl(x) 

else: 

return self._coerce_c_impl(x) 

  

cdef _coerce_c_impl(self, x): # OVERRIDE THIS FOR CYTHON CLASSES 

""" 

Canonically coerce x in assuming that the parent of x is not 

equal to self. 

""" 

check_old_coerce(self) 

raise TypeError 

  

def _coerce_impl(self, x): # OVERRIDE THIS FOR PYTHON CLASSES 

""" 

Canonically coerce x in assuming that the parent of x is not 

equal to self. 

""" 

check_old_coerce(self) 

return self._coerce_c_impl(x) 

  

def _coerce_try(self, x, v): 

""" 

Given a list v of rings, try to coerce x canonically into each 

one in turn. Return the __call__ coercion of the result into 

self of the first canonical coercion that succeeds. Raise a 

TypeError if none of them succeed. 

  

INPUT: 

x -- Python object 

v -- parent object or list (iterator) of parent objects 

""" 

check_old_coerce(self) 

if not isinstance(v, list): 

v = [v] 

  

for R in v: 

try: 

y = R._coerce_(x) 

return self(y) 

except (TypeError, AttributeError) as msg: 

pass 

raise TypeError("no canonical coercion of element into self") 

  

cpdef has_coerce_map_from_c(self, S): 

""" 

Return True if there is a natural map from S to self. 

Otherwise, return False. 

""" 

check_old_coerce(self) 

if self == S: 

return True 

if self._has_coerce_map_from is None: 

self._has_coerce_map_from = MonoDict() 

else: 

try: 

return self._has_coerce_map_from.get(S) 

except KeyError: 

pass 

x = self.has_coerce_map_from_c_impl(S) 

self._has_coerce_map_from.set(S, x) 

return x 

  

cdef has_coerce_map_from_c_impl(self, S): 

check_old_coerce(self) 

if not isinstance(S, parent.Parent): 

return False 

try: 

self._coerce_c((<parent.Parent>S).an_element()) 

except TypeError: 

return False 

return True 

  

def _an_element_impl(self): # override this in Python 

check_old_coerce(self) 

return self._an_element_c_impl() 

  

cdef _an_element_c_impl(self): # override this in Cython 

""" 

Returns an element of self. Want it in sufficient generality 

that poorly-written functions won't work when they're not 

supposed to. This is cached so doesn't have to be super fast. 

""" 

check_old_coerce(self) 

try: 

return self.gen(0) 

except Exception: 

pass 

  

try: 

return self.gen() 

except Exception: 

pass 

  

from sage.rings.infinity import infinity 

for x in ['_an_element_', 'pi', 1.2, 2, 1, 0, infinity]: 

try: 

return self(x) 

except Exception: 

pass 

  

raise NotImplementedError("please implement _an_element_c_impl or _an_element_impl for %s" % self) 

  

def _an_element(self): # do not override this (call from Python) 

check_old_coerce(self) 

return self._an_element_c() 

  

cpdef _an_element_c(self): # do not override this (call from Cython) 

check_old_coerce(self) 

if not self._cache_an_element is None: 

return self._cache_an_element 

if HAS_DICTIONARY(self): 

self._cache_an_element = self._an_element_impl() 

else: 

self._cache_an_element = self._an_element_c_impl() 

return self._cache_an_element 

  

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

# Coercion Compatibility Layer 

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

  

cpdef _coerce_map_from_(self, S): 

if self._element_constructor is None: 

return self.coerce_map_from_c(S) 

else: 

return parent.Parent._coerce_map_from_(self, S) 

  

def _an_element_(self): 

if self._element_constructor is None: 

return self._an_element_c() 

else: 

return parent.Parent._an_element_(self) 

  

cpdef _generic_convert_map(self, S, category=None): 

r""" 

Return a default conversion from ``S``. 

  

EXAMPLES:: 

  

sage: R.<x,y>=QQ[] 

sage: R._generic_convert_map(QQ).category_for() 

Category of sets with partial maps 

  

""" 

if self._element_constructor is None: 

if hasattr(self, '_element_constructor_'): 

assert callable(self._element_constructor_) 

self._element_constructor = self._element_constructor_ 

else: 

from sage.categories.morphism import CallMorphism 

from sage.categories.homset import Hom 

if isinstance(S, type): 

S = Set_PythonType(S) 

return CallMorphism(Hom(S, self)) 

return parent.Parent._generic_convert_map(self, S, category)