| 1092 | |
| 1093 | class Hankel1(BuiltinFunction): |
| 1094 | r""" |
| 1095 | The Hankel function of the first kind |
| 1096 | |
| 1097 | DEFINITION: |
| 1098 | |
| 1099 | .. math:: |
| 1100 | |
| 1101 | H_\nu^{(1)}(z) = J_{\nu}(z) + iY_{\nu}(z) |
| 1102 | |
| 1103 | EXAMPLES:: |
| 1104 | |
| 1105 | sage: hankel1(3, 4.) |
| 1106 | 0.430171473875622 - 0.182022115953485*I |
| 1107 | sage: latex(hankel1(3, x)) |
| 1108 | H_{3}^{(1)}(x) |
| 1109 | sage: hankel1(3., x).series(x == 2, 10).subs(x=3).n() # abs tol 1e-12 |
| 1110 | 0.309062682819597 - 0.512591541605233*I |
| 1111 | sage: hankel1(3, 3.) |
| 1112 | 0.309062722255252 - 0.538541616105032*I |
| 1113 | """ |
| 1114 | def __init__(self): |
| 1115 | BuiltinFunction.__init__(self, 'hankel1', nargs=2, |
| 1116 | conversions=dict(maple='HankelH1', |
| 1117 | mathematica='HankelH1', |
| 1118 | maxima='hankel1', |
| 1119 | sympy='hankel1')) |
| 1120 | |
| 1121 | def _eval_(self, nu, z): |
| 1122 | nu, z = get_coercion_model().canonical_coercion(nu, z) |
| 1123 | if is_inexact(nu) and not isinstance(nu, Expression): |
| 1124 | return self._evalf_(nu, z, parent(nu)) |
| 1125 | return |
| 1126 | |
| 1127 | def _evalf_(self, nu, z, parent): |
| 1128 | from mpmath import hankel1 |
| 1129 | return mpmath_utils.call(hankel1, nu, z, parent=parent) |
| 1130 | |
| 1131 | def _print_latex_(self, nu, z): |
| 1132 | return r"H_{{{}}}^{{(1)}}({})".format(latex(nu), latex(z)) |
| 1133 | |
| 1134 | def _derivative_(self, nu, z, diff_param): |
| 1135 | if diff_param == 1: |
| 1136 | return (nu * hankel1(nu, z)) / z - hankel1(nu + 1, z) |
| 1137 | else: |
| 1138 | raise NotImplementedError('derivative with respect to order') |
| 1139 | |
| 1140 | hankel1 = Hankel1() |
| 1141 | |
| 1142 | |
| 1143 | class Hankel2(BuiltinFunction): |
| 1144 | r""" |
| 1145 | The Hankel function of the second kind |
| 1146 | |
| 1147 | DEFINITION: |
| 1148 | |
| 1149 | .. math:: |
| 1150 | |
| 1151 | H_\nu^{(2)}(z) = J_{\nu}(z) - iY_{\nu}(z) |
| 1152 | |
| 1153 | EXAMPLES:: |
| 1154 | |
| 1155 | sage: hankel2(3, 4.) |
| 1156 | 0.430171473875622 + 0.182022115953485*I |
| 1157 | sage: latex(hankel2(3, x)) |
| 1158 | H_{3}^{(2)}(x) |
| 1159 | sage: hankel2(3., x).series(x == 2, 10).subs(x=3).n() # abs tol 1e-12 |
| 1160 | 0.309062682819597 + 0.512591541605234*I |
| 1161 | sage: hankel2(3, 3.) |
| 1162 | 0.309062722255252 + 0.538541616105032*I |
| 1163 | """ |
| 1164 | def __init__(self): |
| 1165 | BuiltinFunction.__init__(self, 'hankel2', nargs=2, |
| 1166 | conversions=dict(maple='HankelH2', |
| 1167 | mathematica='HankelH2', |
| 1168 | maxima='hankel2', |
| 1169 | sympy='hankel2')) |
| 1170 | |
| 1171 | def _eval_(self, nu, z): |
| 1172 | nu, z = get_coercion_model().canonical_coercion(nu, z) |
| 1173 | if is_inexact(nu) and not isinstance(nu, Expression): |
| 1174 | return self._evalf_(nu, z, parent(nu)) |
| 1175 | return |
| 1176 | |
| 1177 | def _evalf_(self, nu, z, parent): |
| 1178 | from mpmath import hankel2 |
| 1179 | return mpmath_utils.call(hankel2, nu, z, parent=parent) |
| 1180 | |
| 1181 | def _print_latex_(self, nu, z): |
| 1182 | return r"H_{{{}}}^{{(2)}}({})".format(latex(nu), latex(z)) |
| 1183 | |
| 1184 | def _derivative_(self, nu, z, diff_param): |
| 1185 | if diff_param == 1: |
| 1186 | return (Integer(1) / 2) * (hankel2(nu - 1, z) - hankel2(nu + 1, z)) |
| 1187 | else: |
| 1188 | raise NotImplementedError('derivative with respect to order') |
| 1189 | |
| 1190 | hankel2 = Hankel2() |
| 1191 | |
| 1192 | |
| 1193 | class SphericalBesselJ(BuiltinFunction): |
| 1194 | r""" |
| 1195 | The spherical Bessel function of the first kind |
| 1196 | |
| 1197 | DEFINITION: |
| 1198 | |
| 1199 | .. math:: |
| 1200 | |
| 1201 | j_n(z) = \sqrt{\frac{1}{2}\pi/z} J_{n + \frac{1}{2}}(z) |
| 1202 | |
| 1203 | EXAMPLES:: |
| 1204 | |
| 1205 | sage: spherical_bessel_J(3., x).series(x == 2, 10).subs(x=3).n() |
| 1206 | 0.152051648665037 |
| 1207 | sage: spherical_bessel_J(3., 3) |
| 1208 | 0.152051662030533 |
| 1209 | sage: spherical_bessel_J(4, x).simplify() |
| 1210 | -((45/x^2 - 105/x^4 - 1)*sin(x) + 5*(21/x^2 - 2)*cos(x)/x)/x |
| 1211 | sage: latex(spherical_bessel_J(4, x)) |
| 1212 | j_{4}(x) |
| 1213 | """ |
| 1214 | def __init__(self): |
| 1215 | BuiltinFunction.__init__(self, 'spherical_bessel_J', nargs=2, |
| 1216 | conversions=dict(mathematica= |
| 1217 | 'SphericalBesselJ', |
| 1218 | maxima='spherical_bessel_j', |
| 1219 | sympy='jn')) |
| 1220 | |
| 1221 | def _eval_(self, n, z): |
| 1222 | n, z = get_coercion_model().canonical_coercion(n, z) |
| 1223 | if is_inexact(n) and not isinstance(n, Expression): |
| 1224 | return self._evalf_(n, z, parent(n)) |
| 1225 | return |
| 1226 | |
| 1227 | def _evalf_(self, n, z, parent): |
| 1228 | return mpmath_utils.call(spherical_bessel_f, 'besselj', n, z, |
| 1229 | parent=parent) |
| 1230 | |
| 1231 | def _print_latex_(self, n, z): |
| 1232 | return r"j_{{{}}}({})".format(latex(n), latex(z)) |
| 1233 | |
| 1234 | def _derivative_(self, n, z, diff_param): |
| 1235 | if diff_param == 1: |
| 1236 | return (spherical_bessel_J(n - 1, z) - |
| 1237 | ((n + 1) / z) * spherical_bessel_J(n, z)) |
| 1238 | else: |
| 1239 | raise NotImplementedError('derivative with respect to order') |
| 1240 | |
| 1241 | spherical_bessel_J = SphericalBesselJ() |
| 1242 | |
| 1243 | |
| 1244 | class SphericalBesselY(BuiltinFunction): |
| 1245 | r""" |
| 1246 | The spherical Bessel function of the second kind |
| 1247 | |
| 1248 | DEFINITION: |
| 1249 | |
| 1250 | .. math:: |
| 1251 | |
| 1252 | y_n(z) = \sqrt{\frac{1}{2}\pi/z} Y_{n + \frac{1}{2}}(z) |
| 1253 | |
| 1254 | EXAMPLES:: |
| 1255 | |
| 1256 | sage: spherical_bessel_Y(-3, x).simplify() |
| 1257 | ((3/x^2 - 1)*sin(x) - 3*cos(x)/x)/x |
| 1258 | sage: spherical_bessel_Y(3 + 2 * I, 5 - 0.2 * I) |
| 1259 | -0.270205813266440 - 0.615994702714957*I |
| 1260 | sage: integrate(spherical_bessel_Y(0, x), x) |
| 1261 | -1/2*Ei(I*x) - 1/2*Ei(-I*x) |
| 1262 | sage: latex(spherical_bessel_Y(0, x)) |
| 1263 | y_{0}(x) |
| 1264 | """ |
| 1265 | def __init__(self): |
| 1266 | BuiltinFunction.__init__(self, 'spherical_bessel_Y', nargs=2, |
| 1267 | conversions=dict(mathematica= |
| 1268 | 'SphericalBesselY', |
| 1269 | maxima='spherical_bessel_y', |
| 1270 | sympy='yn')) |
| 1271 | |
| 1272 | def _eval_(self, n, z): |
| 1273 | n, z = get_coercion_model().canonical_coercion(n, z) |
| 1274 | if is_inexact(n) and not isinstance(n, Expression): |
| 1275 | return self._evalf_(n, z, parent(n)) |
| 1276 | return |
| 1277 | |
| 1278 | def _evalf_(self, n, z, parent): |
| 1279 | return mpmath_utils.call(spherical_bessel_f, 'bessely', n, z, |
| 1280 | parent=parent) |
| 1281 | |
| 1282 | def _print_latex_(self, n, z): |
| 1283 | return r"y_{{{}}}({})".format(latex(n), latex(z)) |
| 1284 | |
| 1285 | def _derivative_(self, n, z, diff_param): |
| 1286 | if diff_param == 1: |
| 1287 | return (-spherical_bessel_Y(n, z) / (2 * z) + |
| 1288 | (spherical_bessel_Y(n - 1, z) - |
| 1289 | spherical_bessel_Y(n + 1, z)) / 2) |
| 1290 | else: |
| 1291 | raise NotImplementedError('derivative with respect to order') |
| 1292 | |
| 1293 | spherical_bessel_Y = SphericalBesselY() |
| 1294 | |
| 1295 | |
| 1296 | class SphericalHankel1(BuiltinFunction): |
| 1297 | r""" |
| 1298 | The spherical Hankel function of the first kind |
| 1299 | |
| 1300 | DEFINITION: |
| 1301 | |
| 1302 | .. math:: |
| 1303 | |
| 1304 | h_n^{(1)}(z) = \sqrt{\frac{1}{2}\pi/z} H_{n + \frac{1}{2}}^{(1)}(z) |
| 1305 | |
| 1306 | EXAMPLES:: |
| 1307 | |
| 1308 | sage: spherical_hankel1(1, x).simplify() |
| 1309 | -(x + I)*e^(I*x)/x^2 |
| 1310 | sage: spherical_hankel1(3 + 2 * I, 5 - 0.2 * I) |
| 1311 | 1.25375216869913 - 0.518011435921789*I |
| 1312 | sage: integrate(spherical_hankel1(3, x), x) |
| 1313 | Ei(I*x) - 6*gamma(-1, -I*x) - 15*gamma(-2, -I*x) - 15*gamma(-3, -I*x) |
| 1314 | sage: latex(spherical_hankel1(3, x)) |
| 1315 | h_{3}^{(1)}(x) |
| 1316 | """ |
| 1317 | def __init__(self): |
| 1318 | BuiltinFunction.__init__(self, 'spherical_hankel1', nargs=2, |
| 1319 | conversions=dict(mathematica= |
| 1320 | 'SphericalHankelH1', |
| 1321 | maxima='spherical_hankel1')) |
| 1322 | |
| 1323 | def _eval_(self, n, z): |
| 1324 | n, z = get_coercion_model().canonical_coercion(n, z) |
| 1325 | if is_inexact(n) and not isinstance(n, Expression): |
| 1326 | return self._evalf_(n, z, parent(n)) |
| 1327 | return |
| 1328 | |
| 1329 | def _evalf_(self, n, z, parent): |
| 1330 | return mpmath_utils.call(spherical_bessel_f, 'hankel1', n, z, |
| 1331 | parent=parent) |
| 1332 | |
| 1333 | def _print_latex_(self, n, z): |
| 1334 | return r"h_{{{}}}^{{(1)}}({})".format(latex(n), latex(z)) |
| 1335 | |
| 1336 | def _derivative_(self, n, z, diff_param): |
| 1337 | if diff_param == 1: |
| 1338 | return (-spherical_hankel1(n, z) / (2 * z) + |
| 1339 | (spherical_hankel1(n - 1, z) - |
| 1340 | spherical_hankel1(n + 1, z)) / 2) |
| 1341 | else: |
| 1342 | raise NotImplementedError('derivative with respect to order') |
| 1343 | |
| 1344 | spherical_hankel1 = SphericalHankel1() |
| 1345 | |
| 1346 | |
| 1347 | class SphericalHankel2(BuiltinFunction): |
| 1348 | r""" |
| 1349 | The spherical Hankel function of the second kind |
| 1350 | |
| 1351 | DEFINITION: |
| 1352 | |
| 1353 | .. math:: |
| 1354 | |
| 1355 | h_n^{(2)}(z) = \sqrt{\frac{1}{2}\pi/z} H_{n + \frac{1}{2}}^{(2)}(z) |
| 1356 | |
| 1357 | EXAMPLES:: |
| 1358 | |
| 1359 | sage: spherical_hankel2(1, x).simplify() |
| 1360 | -(x - I)*e^(-I*x)/x^2 |
| 1361 | sage: spherical_hankel2(3 + 2*I, 5 - 0.2*I) |
| 1362 | 0.0217627632692163 + 0.0224001906110906*I |
| 1363 | sage: integrate(spherical_hankel2(3, x), x) |
| 1364 | Ei(-I*x) - 6*gamma(-1, I*x) - 15*gamma(-2, I*x) - 15*gamma(-3, I*x) |
| 1365 | sage: latex(spherical_hankel2(3, x)) |
| 1366 | h_{3}^{(2)}(x) |
| 1367 | """ |
| 1368 | def __init__(self): |
| 1369 | BuiltinFunction.__init__(self, 'spherical_hankel2', nargs=2, |
| 1370 | conversions=dict(mathematica= |
| 1371 | 'SphericalHankelH2', |
| 1372 | maxima='spherical_hankel2')) |
| 1373 | |
| 1374 | def _eval_(self, n, z): |
| 1375 | n, z = get_coercion_model().canonical_coercion(n, z) |
| 1376 | if is_inexact(n) and not isinstance(n, Expression): |
| 1377 | return self._evalf_(n, z, parent(n)) |
| 1378 | return |
| 1379 | |
| 1380 | def _evalf_(self, n, z, parent): |
| 1381 | return mpmath_utils.call(spherical_bessel_f, 'hankel2', n, z, |
| 1382 | parent=parent) |
| 1383 | |
| 1384 | def _print_latex_(self, n, z): |
| 1385 | return r"h_{{{}}}^{{(2)}}({})".format(latex(n), latex(z)) |
| 1386 | |
| 1387 | def _derivative_(self, n, z, diff_param): |
| 1388 | if diff_param == 1: |
| 1389 | return (-spherical_hankel2(n, z) / (2 * z) + |
| 1390 | (spherical_hankel2(n - 1, z) - |
| 1391 | spherical_hankel2(n + 1, z)) / 2) |
| 1392 | else: |
| 1393 | raise NotImplementedError('derivative with respect to order') |
| 1394 | |
| 1395 | spherical_hankel2 = SphericalHankel2() |
| 1396 | |
| 1397 | |
| 1398 | def spherical_bessel_f(F, n, z): |
| 1399 | r""" |
| 1400 | Numerically evaluate the spherical version, `f`, of the Bessel function `F` |
| 1401 | by computing `f_n(z) = \sqrt{\frac{1}{2}\pi/z} F_{n + \frac{1}{2}}(z)`. |
| 1402 | According to Abramowitz & Stegun, this identity holds for the Bessel |
| 1403 | functions `J`, `Y`, `K`, `I`, `H^{(1)}`, and `H^{(2)}`. |
| 1404 | |
| 1405 | EXAMPLES:: |
| 1406 | |
| 1407 | sage: from sage.functions.bessel import spherical_bessel_f |
| 1408 | sage: spherical_bessel_f('besselj', 3, 4) |
| 1409 | mpf('0.22924385795503024') |
| 1410 | sage: spherical_bessel_f('hankel1', 3, 4) |
| 1411 | mpc(real='0.22924385795503024', imag='-0.21864196590306359') |
| 1412 | """ |
| 1413 | from mpmath import mp |
| 1414 | ctx = mp |
| 1415 | prec = ctx.prec |
| 1416 | try: |
| 1417 | n = ctx.convert(n) |
| 1418 | z = ctx.convert(z) |
| 1419 | ctx.prec += 10 |
| 1420 | Fz = getattr(ctx, F)(n + 0.5, z) |
| 1421 | hpi = 0.5 * ctx.pi() |
| 1422 | ctx.prec += 10 |
| 1423 | hpioz = hpi / z |
| 1424 | ctx.prec += 10 |
| 1425 | sqrthpioz = ctx.sqrt(hpioz) |
| 1426 | ctx.prec += 10 |
| 1427 | return sqrthpioz * Fz |
| 1428 | finally: |
| 1429 | ctx.prec = prec |
| 1430 | |