首页 > 解决方案 > 针对关键字参数绘制函数会导致 Julia 出错

问题描述

我有一个涉及大量积分和复杂计算的函数,如下所示:

using HCubature
function func(v, x0, y0; rad=1.)

    L = hcubature(r->r[1]*v(x0+r[1]*cos(r[2]), y0+r[1]*sin(r[2])), [0., π/2], [rad, π])[1]
    R = hcubature(r->r[1]*v(x0+r[1]*cos(r[2]), y0+r[1]*sin(r[2])), [0., 0], [rad, π/2])[1]

    return L, R

end

参数v本身就是一个函数。当我尝试根据关键字参数绘制函数时rad,我收到如下错误消息:

x0_, y0_ = 0, 0

rad_ = 0.:0.1:9.

func_array_L = [func(v, x0_, y0_; rad = radius)[1] for radius in rad_]
func_array_R = [func(v, x0_, y0_; rad = radius)[2] for radius in rad_]

plot(rad_, func_array_L)
plot!(rad_, func_array_R)

错误信息包括一个很长的错误信息:Internal error: encountered unexpected error in runtime:然后是一长串目录,然后是以下内容:

MethodError: no method matching string(::Expr)
The applicable method may be too new: running in world age 3820, while current world is 26290.
Closest candidates are:
  string(::Any...) at strings/io.jl:168 (method too new to be called from this world context.)
  string(!Matched::String) at strings/substring.jl:152 (method too new to be called from this world context.)
  string(!Matched::SubString{String}) at strings/substring.jl:153 (method too new to be called from this world context.)
  ...

我还尝试了其他方法,例如将另一个函数声明rad为唯一的参数等,但它们都不起作用。如何解决问题?

标签: functionplotjulia

解决方案


确实错误信息很奇怪,但原因很简单。您还没有定义函数v。您应该先定义它,然后一切都应该按预期工作。

另外请注意,您的大小写错误using HCubature(注意u应该是小写)。此外,为了使绘图工作,您应该首先导入绘图包,例如通过using Plots.

编辑

重现您的问题的基本代码是:

julia> using HCubature

julia> function func(v, x0, y0; rad=1.)
           L = hcubature(r->r[1]*v(x0+r[1]*cos(r[2]), y0+r[1]*sin(r[2])), [0., π/2], [rad, π])[1]
           R = hcubature(r->r[1]*v(x0+r[1]*cos(r[2]), y0+r[1]*sin(r[2])), [0., 0], [rad, π/2])[1]
           return L, R
       end
func (generic function with 1 method)

julia> v = (x,y) -> x
#27 (generic function with 1 method)

julia> x0_, y0_ = 0, 0
(0, 0)

julia> rad_ = 0.:0.1:9.
0.0:0.1:9.0

julia> func_array_L = [func(v, x0_, y0_; rad = radius)[1] for radius in rad_]
Internal error: encountered unexpected error in runtime:
MethodError(f=typeof(Base.string)(), args=(Expr(:<:, :t, :r),), world=0x0000000000000eec)

这似乎是一个错误。我在这里报告了。

一种解决方法

现在 - 解决它的方法是使v类型稳定。有三种示例方法可以做到这一点。

选项1:将其定义为const

const v1 = v

并使用带v1传递的理解而不是v.

选项2:将其包装在let块中:

func_array_L = let v=v
    [func(v, x0_, y0_; rad = radius)[1] for radius in rad_]
end

选项 3:使用以下名称定义函数v

v2(x,y) = v(x,y)

并使用带v2传递的理解而不是v.

或者,您也可以制作x0_y0_成为常量类型(修复其中一个就足够了)以使所有工作正常。例如这个

func_array_L = [func(v, 1, y0_; rad = radius) for radius in rad_]

按预期工作。

补充笔记

map如果在 map 中使用匿名函数而不是理解,则会遇到类似的问题:

map(radius -> func(v, x0_, y0_; rad = radius)[1], rad_)

并且具有名称的普通函数也会产生相同的错误:

v3(radius) = func(v, x0_, y0_; rad = radius)[1]
map(v3, rad_)

但如果您将一个内部函数引入方法表中,它就会开始工作:

v3(radius) = (tmp(x...) = v(x...); func(tmp, x0_, y0_; rad = radius)[1])

现在map(v3, rad_)按预期工作。


推荐阅读