处理朱莉娅中的kwargs类型

时间:2016-09-20 18:56:23

标签: julia

如何在Julia函数中使用kwargs并声明其类型的速度?

function f(x::Float64; kwargs...)
    kwargs = Dict(kwargs)
    if haskey(kwargs, :c)
        c::Float64 = kwargs[:c]
    else
        c::Float64 = 1.0
    end
    return x^2 + c
end

f(0.0, c=10.0)

的产率:

ERROR: LoadError: syntax: multiple type declarations for "c"

当然我可以将函数定义为f(x::Float64, c::Float64=1.0)来实现结果,但是我有许多可选参数,默认值要传递,所以我更喜欢使用kwargs。

感谢。

Related post

2 个答案:

答案 0 :(得分:5)

正如另一个答案所指出的那样,这真的很重要,如果你的类型不稳定。如果你这样做,答案就是分层你的功能。有一个顶层进行类型检查和各种设置,然后调用一个使用dispatch快速的函数。例如,

function f(x::Float64; kwargs...)
    kwargs = Dict(kwargs)
    if haskey(kwargs, :c)
        c = kwargs[:c]
    else
        c = 1.0
    end

    return _f(x,c)
end
_f(x,c) = x^2 + c

如果大部分时间花在内部函数上,那么这将更快(可能不是非常简单的函数)。这也允许非常一般的使用,你有一个关键字参数默认为nothing和do if nothing ...可以设置一个复杂的默认值,而不必担心类型的稳定性,因为它会被屏蔽内功能。

这种高性能类型检查包装器在性能敏感的内部函数之上,在DifferentialEquations.jl中经常使用。查看高级包装器for the SDE solvers,通过确保类型稳定性(内部函数为sde_solve)(或查看solve ODEProblem)来获得良好的加速,这是更复杂,因为它处理转换到不同的pacakges,但它是相同的想法)。

this PR merges之后,可能会对像你这样的小例子做出更简单的回答。

为了解决一些困惑,这里有一个声明表格:

function f(x::Float64; kwargs...)
    local c::Float64 # Ensures the type of `c` will be `Float64`
    kwargs = Dict(kwargs)
    if haskey(kwargs, :c)
        c = float(kwargs[:c])
    else
        c = 1.0
    end

    return x^2 + c
end

这将强制保存到c的任何内容转换为Float64或错误,从而导致类型稳定,但不是解决方案的一般性。你使用什么形式取决于你正在做什么。

最后,还有类型断言,正如@TotalVerb所示:

function f(x::Float64; c::Float64=1.0, kwargs...)
   return x^2 + c
end

那很干净,或者你可以在函数中断言:

  function f(x::Float64; kwargs...)
    kwargs = Dict(kwargs)
    if haskey(kwargs, :c)
        c = float(kwargs[:c])::Float64
    else
        c = 1.0
    end

    return x^2 + c
end

这将导致仅在发生断言的行上进行转换(即@TotalVerb表单不会发送,因此您不能使用c::Int创建另一个函数,并且它只会断言(转换)时首先读入关键字arg)。

摘要

  1. 无论用户使用什么类型_f,第一个解决方案都会在c中调度为类型稳定,因此如果_f是一个长计算,这将得到非常优化的性能,但对于非常快速的调用,它将有调度开销。

  2. 第二个解决方案会通过强制将c设置为Float64的任何内容来强制修复任何类型的稳定性(它会尝试转换,如果不能,则会发生错误)。因此,这会通过强制类型稳定性或错误来获得速度。

  3. 关键字spot中的断言(@ TotalVerb的答案)是最干净的,但稍后不会自动转换(因此您可能会遇到类型不稳定。但如果您以后不小心转换它,那么你有类型稳定性,类型可以被推断,因此你将获得最佳性能)并且你不能将它扩展到函数具有c作为其他类型(无调度)传入的情况。

  4. 最后的解决方案与3完全相同,但不是很好。我不推荐它。如果你正在做一些复杂的断言,你可能正在设计一些错误的东西,或者真的想做一些像第一个那样的东西(在较长的函数调用中调度,类型稳定)。

  5. 但请注意dispatch with version 3 may be fixed in the near future,这将允许您使用c::Float64c::Int(如果需要)具有不同的功能。希望你的解决方案就在这里。

答案 1 :(得分:2)

请注意,声明类型不会提高性能;您可能希望放宽xc上的类型约束,以使您的代码更通用。无论如何,这可能是你想要的:

function f(x::Float64; c::Float64=1.0, kwargs...)
    return x^2 + c
end

请参阅手册的keyword arguments部分。