特殊(besselj)函数矩阵

时间:2018-02-06 01:46:47

标签: julia bessel-functions

我是朱莉娅的新手,所以我欢迎一些改进以下功能的建议,

using SpecialFunctions

function rb(x, nu_max)

  bj = Array{Complex64}(length(x), nu_max)

  nu = 0.5 + (0:nu_max)
  # somehow dot broadcast isn't happy
  # bj .= [ besselj(_nu,_x)*sqrt(pi/2*_x) for _nu in nu, _x in x]

  bj   = [ besselj(_nu,_x)*sqrt(pi/2*_x) for _nu in nu, _x in x]

end

rb(1.0:0.1:2.0, 500)
基本上,我不太确定在这两个参数(x和nu)上获得矩阵的推荐方法是什么。 documentation并没有提供太多信息,但我了解基本的Fortran例程internally loops over nu,所以为了表现,我不想再这样做了。

编辑: 我问过这个目标;为$ x $和$ \ nu $的多个值计算Riccati-Bessel函数$ j_1(x,\ nu),h_1(x,\ nu)$。

我从原始版本中删除了风格问题,专注于这个核心问题。

2 个答案:

答案 0 :(得分:1)

这是一个很好的例子,您可以充分利用广播。看起来您想要xnu之间的笛卡尔积,其中的行由nu的值填充,列为x。这正是广播可以做的事情 - 您只需要重新塑造x,使其在多列中排成一行:

julia> using SpecialFunctions

julia> x = 1.0:0.1:2.0
1.0:0.1:2.0

julia> nu = 0.5 + (0:500)
0.5:1.0:500.5

 # this shows how broadcast works — these are the arguments and their location in the matrix
julia> tuple.(nu, reshape(x, 1, :))
501×11 Array{Tuple{Float64,Float64},2}:
 (0.5, 1.0)    (0.5, 1.1)    …  (0.5, 1.9)    (0.5, 2.0)
 (1.5, 1.0)    (1.5, 1.1)       (1.5, 1.9)    (1.5, 2.0)
 (2.5, 1.0)    (2.5, 1.1)       (2.5, 1.9)    (2.5, 2.0)
 (3.5, 1.0)    (3.5, 1.1)       (3.5, 1.9)    (3.5, 2.0)
 ⋮                           ⋱                ⋮
 (497.5, 1.0)  (497.5, 1.1)     (497.5, 1.9)  (497.5, 2.0)
 (498.5, 1.0)  (498.5, 1.1)     (498.5, 1.9)  (498.5, 2.0)
 (499.5, 1.0)  (499.5, 1.1)     (499.5, 1.9)  (499.5, 2.0)
 (500.5, 1.0)  (500.5, 1.1)  …  (500.5, 1.9)  (500.5, 2.0)

julia> bj = besselj.(nu,reshape(x, 1, :)).*sqrt.(pi/2*reshape(x, 1, :))
501×11 Array{Float64,2}:
 0.841471    0.891207     0.932039     …  0.9463       0.909297
 0.301169    0.356592     0.414341        0.821342     0.870796
 0.0620351   0.0813173    0.103815        0.350556     0.396896
 0.00900658  0.0130319    0.0182194       0.101174     0.121444
 ⋮                                     ⋱               ⋮
 0.0         0.0          0.0             0.0          0.0
 0.0         0.0          0.0             0.0          0.0
 0.0         0.0          0.0             0.0          0.0
 0.0         0.0          0.0          …  0.0          0.0

答案 1 :(得分:0)

阐述我上面的评论。乍一看,一般来说,尝试通过预先分配数组并就地填充它们来避免临时分配(例如使用dot broadcasting)。也可以使用@inbounds

之后给你一个印象
using SpecialFunctions
x = 1.0
nu_max = 3
nu = 0.5 + (0:nu_max)
f(nu,x) = besselj.(nu,x).*sqrt.(pi/2*x)

比较(使用BenchmarkTools

的性能(和分配)
bj   = hcat([ besselj.(_nu,x).*sqrt.(pi/2*x) for _nu in nu]...)

f.(nu,x)

(从技术上讲,输出不相同,你必须使用上面的vcat,但无论如何)

更新(在OP纯化他的代码之后):

好的,我想我(终于)现在看到了你真正的问题(对不起)。我上面所说的是关于如何调用原始代码besselj并有效地处理它的输出(请参阅@Matt B。此处发布的完整广播解决方案)

IIUC,你想在给定besselj和{nu的计算中利用这个事实(我不知道并且没有检查这是否真的存在) {1}}内部有x的总和。换句话说,您希望使用此内部求和的中间结果来避免冗余计算。

由于SpecialFunctions的nu似乎只是调用Fortran例程(可能是here),我怀疑你是否可以访问这些信息。不幸的是,我无法帮助你(我可能会寻找besselj的纯Julia实现。)