# HG changeset patch
# User Flavia Stan <flavia.stan@gmail.com>
# Date 1266276244 -3600
# Node ID 6f981d100b5cf86dea860b77a46e3562f7fbd21e
# Parent e634615fef0a8dc50ab2857b71bd3c03e069ae53
Trac 7748: Make the exponential integral function Ei symbolic.
diff --git a/sage/functions/transcendental.py b/sage/functions/transcendental.py
a
|
b
|
|
18 | 18 | #***************************************************************************** |
19 | 19 | |
20 | 20 | import sys |
21 | | |
| 21 | from sage.libs.mpmath import utils as mpmath_utils |
22 | 22 | import sage.libs.pari.all |
23 | 23 | from sage.libs.pari.all import pari, PariError |
24 | 24 | import sage.rings.complex_field as complex_field |
25 | 25 | import sage.rings.real_double as real_double |
26 | 26 | import sage.rings.complex_number |
27 | 27 | from sage.gsl.integration import numerical_integral |
| 28 | from sage.structure.parent import Parent |
| 29 | from sage.structure.coerce import parent |
| 30 | from sage.symbolic.expression import Expression |
| 31 | from sage.functions.log import exp |
28 | 32 | |
29 | 33 | from sage.rings.all import (is_RealNumber, RealField, |
30 | 34 | is_ComplexNumber, ComplexField, |
31 | 35 | ZZ, RR, RDF, CDF, prime_range) |
32 | 36 | |
33 | | from sage.symbolic.function import BuiltinFunction, SR |
| 37 | from sage.symbolic.function import BuiltinFunction, SR, is_inexact |
34 | 38 | |
35 | 39 | import sage.plot.all |
36 | 40 | |
… |
… |
|
210 | 214 | return R(0.5) |
211 | 215 | |
212 | 216 | return (s/2 + 1).gamma() * (s-1) * (R.pi()**(-s/2)) * s.zeta() |
213 | | |
| 217 | |
214 | 218 | |
215 | 219 | ## # Use PARI on complex nubmer |
216 | 220 | ## prec = s.prec() |
… |
… |
|
230 | 234 | # return real_field.RealField(prec).pi() |
231 | 235 | |
232 | 236 | |
233 | | def Ei(z, prec=None): |
234 | | """ |
235 | | Return the value of the complex exponential integral Ei(z) at a |
236 | | complex number z. |
| 237 | class Function_exp_integral(BuiltinFunction): |
| 238 | def __init__(self): |
| 239 | """ |
| 240 | Return the value of the complex exponential integral Ei(z) at a |
| 241 | complex number z. |
237 | 242 | |
238 | | EXAMPLES:: |
| 243 | EXAMPLES:: |
| 244 | |
| 245 | sage: Ei(10) |
| 246 | Ei(10) |
| 247 | sage: Ei(I) |
| 248 | Ei(I) |
| 249 | sage: Ei(3+I) |
| 250 | Ei(I + 3) |
| 251 | sage: Ei(1.3) |
| 252 | 2.72139888023202 |
| 253 | |
| 254 | The branch cut for this function is along the negative real axis:: |
239 | 255 | |
240 | | sage: Ei(10) |
241 | | 2492.22897624188 |
242 | | sage: Ei(20) |
243 | | 2.56156526640566e7 |
244 | | sage: Ei(I) |
245 | | 0.337403922900968 + 2.51687939716208*I |
246 | | sage: Ei(3+I) |
247 | | 7.82313467600158 + 6.09751978399231*I |
| 256 | sage: Ei(-3 + 0.1*I) |
| 257 | -0.0129379427181693 + 3.13993830250942*I |
| 258 | sage: Ei(-3 - 0.1*I) |
| 259 | -0.0129379427181693 - 3.13993830250942*I |
248 | 260 | |
249 | | The branch cut for this function is along the negative real axis:: |
250 | | |
251 | | sage: Ei(-3 + 0.1*I) |
252 | | -0.0129379427181693 + 3.13993830250942*I |
253 | | sage: Ei(-3 - 0.1*I) |
254 | | -0.0129379427181693 - 3.13993830250942*I |
255 | | |
256 | | ALGORITHM: Uses mpmath. |
257 | | """ |
258 | | if prec is None: |
259 | | try: |
260 | | prec = z.prec() |
261 | | except AttributeError: |
| 261 | ALGORITHM: Uses mpmath. |
| 262 | """ |
| 263 | BuiltinFunction.__init__(self, "Ei") |
| 264 | |
| 265 | def _eval_(self, x ): |
| 266 | """ |
| 267 | EXAMPLES:: |
| 268 | |
| 269 | sage: Ei(10) |
| 270 | Ei(10) |
| 271 | sage: Ei(I) |
| 272 | Ei(I) |
| 273 | sage: Ei(1.3) |
| 274 | 2.72139888023202 |
| 275 | sage: Ei(10r) |
| 276 | Ei(10) |
| 277 | sage: Ei(1.3r) |
| 278 | 2.72139888023202 |
| 279 | """ |
| 280 | if not isinstance(x, Expression) and is_inexact(x): |
| 281 | return self._evalf_(x, parent(x)) |
| 282 | return None |
| 283 | |
| 284 | def _evalf_(self, x, parent=None): |
| 285 | """ |
| 286 | EXAMPLES:: |
| 287 | |
| 288 | sage: Ei(10).n() |
| 289 | 2492.22897624188 |
| 290 | sage: Ei(20).n() |
| 291 | 2.56156526640566e7 |
| 292 | sage: Ei(I).n() |
| 293 | 0.337403922900968 + 2.51687939716208*I |
| 294 | sage: Ei(3+I).n() |
| 295 | 7.82313467600158 + 6.09751978399231*I |
| 296 | """ |
| 297 | import mpmath |
| 298 | if isinstance(parent, Parent) and hasattr(parent, 'prec'): |
| 299 | prec = parent.prec() |
| 300 | else: |
262 | 301 | prec = 53 |
| 302 | return mpmath_utils.call(mpmath.ei, x, prec=prec) |
| 303 | |
| 304 | def __call__(self, x, prec=None, coerce=True, hold=False ): |
| 305 | """ |
| 306 | Note that the ``prec`` argument is deprecated. The precision for |
| 307 | the result is deduced from the precision of the input. Convert |
| 308 | the input to a higher precision explicitly if a result with higher |
| 309 | precision is desired. |
| 310 | |
| 311 | EXAMPLES:: |
| 312 | |
| 313 | sage: t = Ei(RealField(100)(2.5)); t |
| 314 | 7.0737658945786007119235519625 |
| 315 | sage: t.prec() |
| 316 | 100 |
| 317 | |
| 318 | sage: Ei(1.1, prec=300) |
| 319 | doctest:...: DeprecationWarning: The prec keyword argument is deprecated. Explicitly set the precision of the input, for example Ei(RealField(300)(1)), or use the prec argument to .n() for exact inputs, e.g., Ei(1).n(300), instead. |
| 320 | 2.16737827956340306615064476647912607220394065907142504328679588538509331805598360907980986 |
| 321 | """ |
| 322 | if prec is not None: |
| 323 | from sage.misc.misc import deprecation |
| 324 | deprecation("The prec keyword argument is deprecated. Explicitly set the precision of the input, for example Ei(RealField(300)(1)), or use the prec argument to .n() for exact inputs, e.g., Ei(1).n(300), instead.") |
263 | 325 | |
264 | | import sage.libs.mpmath.all as mp |
265 | | return mp.call(mp.ei, z, prec=prec) |
| 326 | import mpmath |
| 327 | return mpmath_utils.call(mpmath.ei, x, prec=prec) |
| 328 | |
| 329 | return BuiltinFunction.__call__(self, x, coerce=coerce, hold=hold) |
| 330 | |
| 331 | def _derivative_(self, x, diff_param=None): |
| 332 | """ |
| 333 | EXAMPLES:: |
| 334 | |
| 335 | sage: Ei(x).diff(x) |
| 336 | e^x/x |
| 337 | sage: Ei(x).diff(x).subs(x=1) |
| 338 | e |
| 339 | sage: Ei(x^2).diff(x) |
| 340 | 2*e^(x^2)/x |
| 341 | sage: f = function('f') |
| 342 | sage: Ei(f(x)).diff(x) |
| 343 | e^f(x)*D[0](f)(x)/f(x) |
| 344 | """ |
| 345 | return exp(x)/x |
| 346 | |
| 347 | Ei = Function_exp_integral() |
| 348 | |
266 | 349 | |
267 | 350 | def Li(x, eps_rel=None, err_bound=False): |
268 | 351 | r""" |
diff --git a/sage/symbolic/function.pyx b/sage/symbolic/function.pyx
a
|
b
|
|
1167 | 1167 | return None |
1168 | 1168 | return unpickle_function(p) |
1169 | 1169 | |
| 1170 | def is_inexact(x): |
| 1171 | """ |
| 1172 | Returns True if the argument is an inexact object. |
| 1173 | |
| 1174 | TESTS:: |
| 1175 | |
| 1176 | sage: from sage.symbolic.function import is_inexact |
| 1177 | sage: is_inexact(5) |
| 1178 | False |
| 1179 | sage: is_inexact(5.) |
| 1180 | True |
| 1181 | sage: is_inexact(pi) |
| 1182 | True |
| 1183 | sage: is_inexact(5r) |
| 1184 | False |
| 1185 | sage: is_inexact(5.4r) |
| 1186 | True |
| 1187 | """ |
| 1188 | if isinstance(x, (float, complex)): |
| 1189 | return True |
| 1190 | if isinstance(x, Element): |
| 1191 | return not (<Element>x)._parent.is_exact() |
| 1192 | return False |
diff --git a/sage/symbolic/random_tests.py b/sage/symbolic/random_tests.py
a
|
b
|
|
202 | 202 | |
203 | 203 | sage: from sage.symbolic.random_tests import * |
204 | 204 | sage: random_expr(50, nvars=3, coeff_generator=CDF.random_element) |
205 | | sinh(sinh(-coth(v2)/erf(-(0.615863165633 + 0.879368031485*I)*v1^2*v3) - gamma(pi) + csch(-(0.708874026302 - 0.954135400334*I)*v3)))^coth(-cosh(-polylog((v2 + 0.913564344312 + 0.0898040160336*I)^(-(0.723896589334 - 0.799038508886*I)*v2), -v1 - v3))/arcsin(-(0.0263902659909 + 0.153261789843*I)*arctan2(pi, arccot(pi)))) |
| 205 | sinh(arcsech(-heaviside(v2)/erf(-(0.615863165633 + 0.879368031485*I)*v1^2*v3) - gamma(pi) + erf(-(0.708874026302 - 0.954135400334*I)*v3)))^coth(-cosh(-polylog((v2 + 0.913564344312 + 0.0898040160336*I)^(-(0.723896589334 - 0.799038508886*I)*v2), -v1 - v3))/dilog(-(0.0263902659909 + 0.153261789843*I)*arctan2(pi, arccot(pi)))) |
206 | 206 | sage: random_expr(5, verbose=True) |
207 | 207 | About to apply <built-in function add> to [v1, v1] |
208 | 208 | About to apply <built-in function div> to [-1/3, 2*v1] |