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

""" 

Fast functions for the category framework 

  

  

AUTHOR: 

  

- Simon King (initial version) 

  

""" 

  

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

# Copyright (C) 2014 Simon King <simon.king@uni-jena.de> 

# 

# 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/ 

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

  

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

## Sorting 

  

cpdef inline tuple category_sort_key(object category): 

""" 

Return ``category._cmp_key``. 

  

This helper function is used for sorting lists of categories. 

  

It is semantically equivalent to 

:func:`operator.attrgetter` ``("_cmp_key")``, but currently faster. 

  

EXAMPLES:: 

  

sage: from sage.categories.category_cy_helper import category_sort_key 

sage: category_sort_key(Rings()) is Rings()._cmp_key 

True 

""" 

return category._cmp_key 

  

cpdef tuple _sort_uniq(categories): 

""" 

Return the categories after sorting them and removing redundant categories. 

  

Redundant categories include duplicates and categories which 

are super categories of other categories in the input. 

  

INPUT: 

  

- ``categories`` -- a list (or iterable) of categories 

  

OUTPUT: a sorted tuple of mutually incomparable categories 

  

EXAMPLES:: 

  

sage: Category._sort_uniq([Rings(), Monoids(), Coalgebras(QQ)]) 

(Category of rings, Category of coalgebras over Rational Field) 

  

Note that, in the above example, ``Monoids()`` does not appear 

in the result because it is a super category of ``Rings()``. 

""" 

cdef tuple cats = tuple(sorted(categories, key=category_sort_key, reverse=True)) 

cdef list result = [] 

cdef bint append 

for category in cats: 

append = True 

for cat in result: 

if cat.is_subcategory(category): 

append = False 

break 

if append: 

result.append(category) 

return tuple(result) 

  

cpdef tuple _flatten_categories(categories, ClasscallMetaclass JoinCategory): 

""" 

Return the tuple of categories in ``categories``, while 

flattening join categories. 

  

INPUT: 

  

- ``categories`` -- a list (or iterable) of categories 

  

- ``JoinCategory`` -- A type such that instances of that type will be 

replaced by its super categories. Usually, this type is 

:class:`JoinCategory`. 

  

.. NOTE:: 

  

It is needed to provide :class:`~sage.categories.category.JoinCategory` as 

an argument, since we need to prevent a circular import. 

  

EXAMPLES:: 

  

sage: Category._flatten_categories([Algebras(QQ), Category.join([Monoids(), Coalgebras(QQ)]), Sets()], sage.categories.category.JoinCategory) 

(Category of algebras over Rational Field, Category of monoids, 

Category of coalgebras over Rational Field, Category of sets) 

""" 

# Invariant: the super categories of a JoinCategory are not JoinCategories themselves 

cdef list out = [] 

for category in categories: 

if isinstance(category, JoinCategory): 

out.extend(category.super_categories()) 

else: 

out.append(category) 

return tuple(out) 

  

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

## Join 

  

cdef bint is_supercategory_of_done(new_cat, dict done): 

# This is a helper function. It replaces the closure 

# any(cat.is_subcategory(new_cat) for cat in done) 

for cat in done: 

if cat.is_subcategory(new_cat): 

return True 

return False 

  

cpdef tuple join_as_tuple(tuple categories, tuple axioms, tuple ignore_axioms): 

""" 

Helper for :meth:`~sage.categories.category.Category.join`. 

  

INPUT: 

  

- ``categories`` -- tuple of categories to be joined, 

- ``axioms`` -- tuple of strings; the names of some 

supplementary axioms. 

- ``ignore_axioms`` -- tuple of pairs ``(cat, axiom)``, such 

that ``axiom`` will not be applied to ``cat``, should ``cat`` 

occur in the algorithm. 

  

EXAMPLES:: 

  

sage: from sage.categories.category_cy_helper import join_as_tuple 

sage: T = (Coalgebras(QQ), Sets().Finite(), Algebras(ZZ), SimplicialComplexes()) 

sage: join_as_tuple(T,(),()) 

(Category of algebras over Integer Ring, 

Category of finite monoids, 

Category of finite additive groups, 

Category of coalgebras over Rational Field, 

Category of finite simplicial complexes) 

sage: join_as_tuple(T,('WithBasis',),()) 

(Category of algebras with basis over Integer Ring, 

Category of finite monoids, 

Category of coalgebras with basis over Rational Field, 

Category of finite additive groups, 

Category of finite simplicial complexes) 

sage: join_as_tuple(T,(),((Monoids(),'Finite'),)) 

(Category of algebras over Integer Ring, 

Category of finite additive groups, 

Category of coalgebras over Rational Field, 

Category of finite simplicial complexes) 

""" 

cdef set axiomsS = set(axioms) 

for category in categories: 

axiomsS.update(category.axioms()) 

cdef dict done = dict() 

cdef set todo = set() 

cdef frozenset axs 

for category in categories: 

axs = category.axioms() 

for (cat, axiom) in ignore_axioms: 

if category.is_subcategory(cat): 

axs = axs | {axiom} 

done[category] = axs 

for axiom in axiomsS.difference(axs): 

todo.add( (category, axiom) ) 

  

# Invariants: 

# - the current list of categories is stored in the keys of ``done`` 

# - todo contains the ``complement`` of done; i.e. 

# for category in the keys of done, 

# (category, axiom) is in todo iff axiom is not in done[category] 

cdef list new_cats 

cdef set new_axioms 

while todo: 

(category, axiom) = todo.pop() 

# It's easier to remove categories from done than from todo 

# So we check that ``category`` had not been removed 

if category not in done: 

continue 

  

# Removes redundant categories 

new_cats = [new_cat for new_cat in <tuple>(category._with_axiom_as_tuple(axiom)) 

if not is_supercategory_of_done(new_cat, done)] 

for cat in list(done.keys()): 

for new_cat in new_cats: 

if new_cat.is_subcategory(cat): 

del done[cat] 

break 

  

new_axioms = set() 

for new_cat in new_cats: 

for axiom in new_cat.axioms(): 

if axiom not in axiomsS: 

new_axioms.add(axiom) 

  

# Mark old categories with new axioms as todo 

for category in done: 

for axiom in new_axioms: 

todo.add( (category, axiom) ) 

for new_cat in new_cats: 

axs = new_cat.axioms() 

for (cat, axiom) in ignore_axioms: 

if new_cat.is_subcategory(cat): 

axs = axs | {axiom} 

done[new_cat] = axs 

for axiom in axiomsS.difference(axs): 

todo.add( (new_cat, axiom) ) 

  

return _sort_uniq(done) 

  

  

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

## Axiom related functions 

  

cdef class AxiomContainer(dict): 

""" 

A fast container for axioms. 

  

This is derived from :class:`dict`. A key is the name of an axiom. The 

corresponding value is the "rank" of this axiom, that is used to order the 

axioms in :func:`canonicalize_axioms`. 

  

EXAMPLES:: 

  

sage: all_axioms = sage.categories.category_with_axiom.all_axioms 

sage: isinstance(all_axioms, sage.categories.category_with_axiom.AxiomContainer) 

True 

""" 

def add(self, axiom): 

""" 

Add a new axiom name, of the next rank. 

  

EXAMPLES:: 

  

sage: all_axioms = sage.categories.category_with_axiom.all_axioms 

sage: m = max(all_axioms.values()) 

sage: all_axioms.add('Awesome') 

sage: all_axioms['Awesome'] == m + 1 

True 

  

To avoid side effects, we remove the added axiom:: 

  

sage: del all_axioms['Awesome'] 

""" 

self[axiom] = len(self) 

  

def __iadd__(self, L): 

""" 

Inline addition, which means to add a list of axioms to the container. 

  

EXAMPLES:: 

  

sage: all_axioms = sage.categories.category_with_axiom.all_axioms 

sage: m = max(all_axioms.values()) 

sage: all_axioms += ('Fancy', 'Awesome') 

sage: all_axioms['Awesome'] == m + 2 

True 

  

To avoid side effects, we delete the axioms that we just added:: 

  

sage: del all_axioms['Awesome'], all_axioms['Fancy'] 

""" 

for axiom in L: 

self.add(axiom) 

return self 

  

  

cpdef inline get_axiom_index(AxiomContainer all_axioms, str axiom): 

""" 

Helper function: Return the rank of an axiom. 

  

INPUT: 

  

- ``all_axioms`` -- the axiom collection 

- ``axiom`` -- string, name of an axiom 

  

EXAMPLES:: 

  

sage: all_axioms = sage.categories.category_with_axiom.all_axioms 

sage: from sage.categories.category_cy_helper import get_axiom_index 

sage: get_axiom_index(all_axioms, 'AdditiveCommutative') == all_axioms['AdditiveCommutative'] 

True 

""" 

return (<dict>all_axioms)[axiom] 

  

  

cpdef tuple canonicalize_axioms(AxiomContainer all_axioms, axioms): 

r""" 

Canonicalize a set of axioms. 

  

INPUT: 

  

- ``all_axioms`` -- all available axioms 

  

- ``axioms`` -- a set (or iterable) of axioms 

  

.. NOTE:: 

  

:class:`AxiomContainer` provides a fast container for axioms, and the 

collection of axioms is stored in 

:mod:`sage.categories.category_with_axiom`. In order to avoid circular 

imports, we expect that the collection of all axioms is provided as an 

argument to this auxiliary function. 

  

OUTPUT: 

  

A set of axioms as a tuple sorted according to the order of the 

tuple ``all_axioms`` in :mod:`sage.categories.category_with_axiom`. 

  

EXAMPLES:: 

  

sage: from sage.categories.category_with_axiom import canonicalize_axioms, all_axioms 

sage: canonicalize_axioms(all_axioms, ["Commutative", "Connected", "WithBasis", "Finite"]) 

('Finite', 'Connected', 'WithBasis', 'Commutative') 

sage: canonicalize_axioms(all_axioms, ["Commutative", "Connected", "Commutative", "WithBasis", "Finite"]) 

('Finite', 'Connected', 'WithBasis', 'Commutative') 

""" 

cdef list L = list(set(axioms)) 

L.sort(key = (all_axioms).__getitem__) 

return tuple(L)