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

r""" 

Evaluating a String in Sage 

""" 

 

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

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

# 

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

# 

# http://www.gnu.org/licenses/ 

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

 

from __future__ import absolute_import, division 

import six 

from copy import copy 

import sage.repl.preparse as preparser 

 

def sage_eval(source, locals=None, cmds='', preparse=True): 

r""" 

Obtain a Sage object from the input string by evaluating it using 

Sage. This means calling eval after preparsing and with globals 

equal to everything included in the scope of ``from sage.all 

import *``.). 

 

INPUT: 

 

 

- ``source`` - a string or object with a _sage_ 

method 

 

- ``locals`` - evaluate in namespace of sage.all plus 

the locals dictionary 

 

- ``cmds`` - string; sequence of commands to be run 

before source is evaluated. 

 

- ``preparse`` - (default: True) if True, preparse the 

string expression. 

 

 

EXAMPLES: This example illustrates that preparsing is applied. 

 

:: 

 

sage: eval('2^3') 

1 

sage: sage_eval('2^3') 

8 

 

However, preparsing can be turned off. 

 

:: 

 

sage: sage_eval('2^3', preparse=False) 

1 

 

Note that you can explicitly define variables and pass them as the 

second option:: 

 

sage: x = PolynomialRing(RationalField(),"x").gen() 

sage: sage_eval('x^2+1', locals={'x':x}) 

x^2 + 1 

 

This example illustrates that evaluation occurs in the context of 

``from sage.all import *``. Even though bernoulli has 

been redefined in the local scope, when calling 

``sage_eval`` the default value meaning of bernoulli 

is used. Likewise for QQ below. 

 

:: 

 

sage: bernoulli = lambda x : x^2 

sage: bernoulli(6) 

36 

sage: eval('bernoulli(6)') 

36 

sage: sage_eval('bernoulli(6)') 

1/42 

 

:: 

 

sage: QQ = lambda x : x^2 

sage: QQ(2) 

4 

sage: sage_eval('QQ(2)') 

2 

sage: parent(sage_eval('QQ(2)')) 

Rational Field 

 

This example illustrates setting a variable for use in evaluation. 

 

:: 

 

sage: x = 5 

sage: eval('4/3 + x', {'x': 25}) # py2 

26 

sage: eval('4//3 + x', {'x': 25}) # py3 

26 

sage: sage_eval('4/3 + x', locals={'x': 25}) 

79/3 

 

You can also specify a sequence of commands to be run before the 

expression is evaluated:: 

 

sage: sage_eval('p', cmds='K.<x> = QQ[]\np = x^2 + 1') 

x^2 + 1 

 

If you give commands to execute and a dictionary of variables, then 

the dictionary will be modified by assignments in the commands:: 

 

sage: vars = {} 

sage: sage_eval('None', cmds='y = 3', locals=vars) 

sage: vars['y'], parent(vars['y']) 

(3, Integer Ring) 

 

You can also specify the object to evaluate as a tuple. A 2-tuple 

is assumed to be a pair of a command sequence and an expression; a 

3-tuple is assumed to be a triple of a command sequence, an 

expression, and a dictionary holding local variables. (In this 

case, the given dictionary will not be modified by assignments in 

the commands.) 

 

:: 

 

sage: sage_eval(('f(x) = x^2', 'f(3)')) 

9 

sage: vars = {'rt2': sqrt(2.0)} 

sage: sage_eval(('rt2 += 1', 'rt2', vars)) 

2.41421356237309 

sage: vars['rt2'] 

1.41421356237310 

 

This example illustrates how ``sage_eval`` can be 

useful when evaluating the output of other computer algebra 

systems. 

 

:: 

 

sage: R.<x> = PolynomialRing(RationalField()) 

sage: gap.eval('R:=PolynomialRing(Rationals,["x"]);') 

'Rationals[x]' 

sage: ff = gap.eval('x:=IndeterminatesOfPolynomialRing(R);; f:=x^2+1;'); ff 

'x^2+1' 

sage: sage_eval(ff, locals={'x':x}) 

x^2 + 1 

sage: eval(ff) 

Traceback (most recent call last): 

... 

RuntimeError: Use ** for exponentiation, not '^', which means xor 

in Python, and has the wrong precedence. 

 

Here you can see eval simply will not work but 

``sage_eval`` will. 

 

TESTS: 

 

We get a nice minimal error message for syntax errors, that still 

points to the location of the error (in the input string):: 

 

sage: sage_eval('RR(22/7]') 

Traceback (most recent call last): 

... 

File "<string>", line 1 

RR(Integer(22)/Integer(7)] 

^ 

SyntaxError: unexpected EOF while parsing 

 

:: 

 

sage: sage_eval('None', cmds='$x = $y[3] # Does Perl syntax work?') 

Traceback (most recent call last): 

... 

File "<string>", line 1 

$x = $y[Integer(3)] # Does Perl syntax work? 

^ 

SyntaxError: invalid syntax 

""" 

if isinstance(source, (list, tuple)): 

cmds = source[0] 

if len(source) > 2: 

locals = copy(source[2]) 

source = source[1] 

 

if not isinstance(source, six.string_types): 

raise TypeError("source must be a string.") 

 

if locals is None: 

locals = {} 

 

import sage.all 

if len(cmds): 

cmd_seq = cmds + '\n_sage_eval_returnval_ = ' + source 

if preparse: 

cmd_seq = preparser.preparse_file(cmd_seq) 

else: 

if preparse: 

source = preparser.preparse(source) 

 

if len(cmds): 

exec(cmd_seq, sage.all.__dict__, locals) 

return locals['_sage_eval_returnval_'] 

else: 

return eval(source, sage.all.__dict__, locals) 

 

 

 

def sageobj(x, vars=None): 

""" 

Return a native Sage object associated to x, if possible and 

implemented. 

 

If the object has an _sage_ method it is called and the value is 

returned. Otherwise str is called on the object, and all preparsing 

is applied and the resulting expression is evaluated in the context 

of ``from sage.all import *``. To evaluate the 

expression with certain variables set, use the vars argument, which 

should be a dictionary. 

 

EXAMPLES:: 

 

sage: type(sageobj(gp('34/56'))) 

<type 'sage.rings.rational.Rational'> 

sage: n = 5/2 

sage: sageobj(n) is n 

True 

sage: k = sageobj('Z(8^3/1)', {'Z':ZZ}); k 

512 

sage: type(k) 

<type 'sage.rings.integer.Integer'> 

 

This illustrates interfaces:: 

 

sage: f = gp('2/3') 

sage: type(f) 

<class 'sage.interfaces.gp.GpElement'> 

sage: f._sage_() 

2/3 

sage: type(f._sage_()) 

<type 'sage.rings.rational.Rational'> 

sage: a = gap(939393/2433) 

sage: a._sage_() 

313131/811 

sage: type(a._sage_()) 

<type 'sage.rings.rational.Rational'> 

""" 

try: 

return x._sage_() 

except (TypeError, NotImplementedError, AttributeError): 

return sage_eval(str(x), vars)