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

# -*- coding: utf-8 -*- 

""" 

Poor Man's map 

""" 

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

# Copyright (C) 2009 Nicolas M. Thiery <nthiery at users.sf.net> 

# 2016 Julian Rüth <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/ 

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

import sage.structure.sage_object 

 

class PoorManMap(sage.structure.sage_object.SageObject): 

""" 

A class for maps between sets which are not (yet) modeled by parents 

 

Could possibly disappear when all combinatorial classes / enumerated sets will be parents 

 

INPUT: 

 

- ``function`` -- a callable or an iterable of callables. This represents 

the underlying function used to implement this map. If it is an iterable, 

then the callables will be composed to implement this map. 

 

- ``domain`` -- the domain of this map or ``None`` if the domain is not 

known or should remain unspecified 

 

- ``codomain`` -- the codomain of this map or ``None`` if the codomain is 

not known or should remain unspecified 

 

- ``name`` -- a name for this map or ``None`` if this map has no particular 

name 

 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(factorial, domain = (1, 2, 3), codomain = (1, 2, 6)) 

sage: f 

A map from (1, 2, 3) to (1, 2, 6) 

sage: f(3) 

6 

 

The composition of several functions can be created by passing in a tuple 

of functions:: 

 

sage: i = PoorManMap((factorial, sqrt), domain= (1, 4, 9), codomain = (1, 2, 6)) 

 

However, the same effect can also be achieved by just composing maps:: 

 

sage: g = PoorManMap(factorial, domain = (1, 2, 3), codomain = (1, 2, 6)) 

sage: h = PoorManMap(sqrt, domain = (1, 4, 9), codomain = (1, 2, 3)) 

sage: i == g*h 

True 

 

""" 

def __init__(self, function, domain = None, codomain = None, name = None): 

""" 

TESTS:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(factorial, domain = (1, 2, 3), codomain = (1, 2, 6)) 

sage: g = PoorManMap(sqrt, domain = (1, 4, 9), codomain = (1, 2, 6)) 

 

sage: TestSuite(f).run() 

sage: TestSuite(f*g).run() 

 

""" 

from collections import Iterable 

if not isinstance(function, Iterable): 

function = (function,) 

self._functions = tuple(function) 

self._domain = domain 

self._codomain = codomain 

self._name = name 

 

def _repr_(self): 

""" 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: PoorManMap(lambda x: x+2) # indirect doctest 

A map 

sage: PoorManMap(lambda x: x+2, domain = (1,2,3)) 

A map from (1, 2, 3) 

sage: PoorManMap(lambda x: x+2, domain = (1,2,3)) 

A map from (1, 2, 3) 

sage: PoorManMap(lambda x: x+2, codomain = (3,4,5)) 

A map to (3, 4, 5) 

 

""" 

return ((self._name if self._name is not None else "A map") + 

(" from %s"%(self._domain,) if self._domain is not None else "" ) + 

(" to %s"%(self._codomain,) if self._codomain is not None else "" )) 

 

def domain(self): 

""" 

Returns the domain of ``self`` 

 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)).domain() 

(1, 2, 3) 

""" 

return self._domain 

 

def codomain(self): 

""" 

Returns the codomain of ``self`` 

 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)).codomain() 

(2, 3, 4) 

""" 

return self._codomain 

 

def __eq__(self, other): 

r""" 

Return whether this map is equal to ``other``. 

 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) 

sage: g = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) 

sage: h1 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) 

sage: h2 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) 

sage: h3 = PoorManMap(factorial, domain = (1,2,3,4), codomain = (1,2,6)) 

sage: h4 = PoorManMap(lambda x: x, domain = (1,2,3), codomain = (1,2,6)) 

sage: f == g, f == h1, f == h2, f == h3, f == h4, f == 1, 1 == f 

(True, False, False, False, False, False, False) 

 

""" 

if isinstance(other, PoorManMap): 

return (self._functions == other._functions 

and self._domain == other._domain 

and self._codomain == other._codomain 

and self._name == other._name) 

else: 

return False 

 

def __ne__(self, other): 

r""" 

Return whether this map is not equal to ``other``. 

 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) 

sage: g = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) 

sage: h1 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) 

sage: h2 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) 

sage: h3 = PoorManMap(factorial, domain = (1,2,3,4), codomain = (1,2,6)) 

sage: h4 = PoorManMap(lambda x: x, domain = (1,2,3), codomain = (1,2,6)) 

sage: f != g, f != h1, f != h2, f != h3, f != h4, f != 1, 1 != f 

(False, True, True, True, True, True, True) 

 

""" 

return not (self == other) 

 

def __hash__(self): 

r""" 

Return a hash value for this map. 

 

TESTS:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) 

sage: g = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) 

sage: hash(f) == hash(g) 

True 

 

""" 

return hash((self._functions, self._domain, self._codomain, self._name)) 

 

def __mul__(self, other): 

""" 

Composition 

 

INPUT: 

- ``self`` -- a map `f` 

- ``other`` -- a map `g` 

 

Returns the composition map `f\circ g` of `f`` and `g` 

 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)) 

sage: g = PoorManMap(lambda x: -x, domain = (2,3,4), codomain = (-2,-3,-4)) 

sage: g*f 

A map from (1, 2, 3) to (-2, -3, -4) 

 

Note that the compatibility of the domains and codomains is for performance 

reasons only checked for proper parents. For example, the incompatibility 

is not detected here:: 

 

sage: f*g 

A map from (2, 3, 4) to (2, 3, 4) 

 

But it is detected here:: 

 

sage: g = PoorManMap(factorial, domain = ZZ, codomain = ZZ) 

sage: h = PoorManMap(sqrt, domain = RR, codomain = CC) 

sage: g*h 

Traceback (most recent call last): 

... 

ValueError: the codomain Complex Field with 53 bits of precision does not coerce into the domain Integer Ring 

sage: h*g 

A map from Integer Ring to Complex Field with 53 bits of precision 

 

""" 

self_domain = self.domain() 

 

try: 

other_codomain = other.codomain() 

except AttributeError: 

other_codomain = None 

 

if self_domain is not None and other_codomain is not None: 

from sage.structure.parent import is_Parent 

if is_Parent(self_domain) and is_Parent(other_codomain): 

if not self_domain.has_coerce_map_from(other_codomain): 

raise ValueError("the codomain %r does not coerce into the domain %r"%(other_codomain, self_domain)) 

 

codomain = self.codomain() 

try: 

domain = other.domain() 

except AttributeError: 

domain = None 

 

if isinstance(other, PoorManMap): 

other = other._functions 

else: 

other = (other,) 

 

return PoorManMap(self._functions + other, domain=domain, codomain=codomain) 

 

def __call__(self, *args): 

""" 

EXAMPLES:: 

 

sage: from sage.categories.poor_man_map import PoorManMap 

sage: f = PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)) 

sage: f(2) 

3 

 

sage: g = PoorManMap(lambda x: -x, domain = (2,3,4), codomain = (-2,-3,-4)) 

sage: (g*f)(2) 

-3 

 

""" 

for function in reversed(self._functions): 

args = [function(*args)] 

return args[0]