Julia 特殊(besselj)函数矩阵

Julia 特殊(besselj)函数矩阵,julia,bessel-functions,Julia,Bessel Functions,我是julia的新手,所以我希望能得到一些建议来改进以下功能 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]

我是julia的新手,所以我希望能得到一些建议来改进以下功能

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)上得到矩阵的推荐方法是什么。虽然没有提供太多的信息,但我了解底层的fortran例程,所以为了性能起见,我不想再这样做了


编辑: 有人问我目标是什么;对于$x$和$\nu$的多个值,计算Riccati-Bessel函数$j_1(x,\nu)、h_1(x,\nu)$


我已经将原文中的文体问题剥离出来,以关注这一核心问题。

详细阐述我的上述评论。乍一看,一般来说,通过预先分配数组并将其填充到位(例如使用)来避免临时分配。也可以使用
@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)
比较(使用)性能(和分配)

f.(nu,x)

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

更新(OP净化其代码后):

好的,我想我(终于)明白你真正的问题了(很抱歉)。我上面所说的是关于优化您的原始代码,使其能够调用
besselj
,并有效地处理其输出(请参阅@Matt B.的文章,了解这里的nice完整广播解决方案)

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


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

这是一个很好的例子,您可以充分利用广播。看起来您需要
x
nu
之间的笛卡尔乘积,其中行由
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

我建议你澄清一下你的目标是什么。写下一个简单的数学公式,然后人们可以尝试回答它。乍一看,一般来说,通过预先分配数组并将其填充到位(例如使用)来避免临时分配。也可以使用
@inbounds
。另外,您正在运行哪个版本?对于Julia 0.6及更高版本,贝塞尔函数已被移动到
特殊函数
。@crstnbr感谢您的建议。我在预分配数组(“维度不匹配”)时出错,即使它是正确的维度。我猜这与右边的理解有关。你能展示一下,如果x是一个数值向量,你会怎么做吗?正如我所说,我不喜欢混合理解和点广播,但对于这个特定的函数(fortran例程一次返回一个数组),nu的处理方式应该与x不同。首先,你可以给f一个
nu
和一个向量
x
,然后再次使用
f.(nu,x)
,不要在你的案例中使用理解。为什么要用相同的内部for循环编写两个理解(即
for _nuin nu
等)?明确地编写循环。我建议你试着用我的评论重写代码,并更新你的帖子。那么我们就有了一个更好的讨论基础。好的,我已经把这个例子删去,进入问题的核心。我同意,对于任何其他函数,在我的原始问题中编写一个for循环都是有意义的;然而,这里的关键是,在fortran.Nice writeup中,besselj在nu值上循环。但OP可能是在要求其他东西(见我的帖子更新)。OP可能应该澄清一下。关于矩阵构造,我相信使用两个循环或广播的理解同样快。感谢这个例子,我认为我必须手动创建x和nu的所有组合,以利用点广播,但这要干净得多。再说一次,如果理解速度也一样快,我不确定这里更喜欢哪一种,可能是口味的问题吧?无论如何,很抱歉,原来的问题将各种问题混为一谈–我主要关心的是Amos的besselj应该返回1:nu的所有值(即这里的一整列)。如果你在茱莉亚一个接一个地这样做,速度会慢500倍
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