Julia 定义一个只需少量更改的新方法
我想写一个接受补充论点的版本。与初始版本的区别只存在于几行代码中,可能在循环中。一个典型的例子是使用权重向量Julia 定义一个只需少量更改的新方法,julia,Julia,我想写一个接受补充论点的版本。与初始版本的区别只存在于几行代码中,可能在循环中。一个典型的例子是使用权重向量w 一种解决方案是完全重写一个新函数 function f(Vector::a) ... for x in a ... s += x[i] ... end ... end function f(a::Vector, w::Vector) ... for x in a ... s += x[i]
w
一种解决方案是完全重写一个新函数
function f(Vector::a)
...
for x in a
...
s += x[i]
...
end
...
end
function f(a::Vector, w::Vector)
...
for x in a
...
s += x[i] * w[i]
...
end
...
end
此解决方案复制代码,因此使程序更难维护。
我可以将…
拆分为不同的助手函数,这两个函数都会调用,但生成的代码很难理解
另一种解决方案是只编写一个函数并使用?:代码>应更改的每行的结构
function f(a, w::Union(Nothing, Vector) = nothing)
....
for x in a
...
s += (w == nothing)? x[i] : x[i] * w[i]
...
end
....
end
这段代码需要在循环的每一步检查一个条件,与第一个版本相比,这听起来效率不高
我相信有更好的解决方案,也许是使用宏。处理这个问题的好方法是什么?在这种情况下,使用可能会起到关键作用
只需将w
参数默认为ones()
我已经多次遇到这个问题。如果要避免循环中的条件If语句,一种可能是对某些伪类型使用多个分派。例如:
abstract MyFuncTypes
type FuncWithNoWeight <: MyFuncTypes; end
evaluate(x::Vector, i::Int, ::FuncWithNoWeight) = x[i]
type FuncWithWeight{T} <: MyFuncTypes
w::Vector{T}
end
evaluate(x::Vector, i::Int, wT::FuncWithWeight) = x[i] * wT.w[i]
function f(a, w::MyFuncTypes=FuncWithNoWeight())
....
for x in a
...
s += evaluate(x, i, w)
...
end
....
end
抽象类型
类型FuncWithNoWeight有很多方法可以做这类事情,从可选参数到自定义类型,再到使用@eval
'生成代码的元编程(这将在循环一系列可能性时加入每个新方法的更改)
我认为在这种情况下,我会结合使用@ColinTBowers和@GnimucKey建议的方法
定义一个自定义数组类型非常简单,它都是one
:
immutable Ones{N} <: AbstractArray{Int,N}
dims::NTuple{N, Int}
end
Base.size(O::Ones) = O.dims
Base.getindex(O::Ones, I::Int...) = (checkbounds(O, I...); 1)
这应该比其他建议的解决方案具有更低的开销getindex
应该作为边界检查和数字1
很好地内联,没有类型不稳定性,并且不需要重写算法。如果您确定所有访问都在边界内,您甚至可以将边界检查作为额外的优化删除。或者在最近的0.4上,您可以定义并使用Base.unsafe_getindex(O::Ones,I::Int…)=1
(这在0.3上不太有效,因为不能保证为所有抽象数组定义它)。您可以在循环开始之前进行检查,并将结果设置为布尔变量。谢谢。但是假设x[i]
是一个int,而x[i]w[i]
是一个float。这不会导致类型不稳定吗?在上面的代码中,dummyType仍然是类型不稳定的。虽然我不认为它会导致很多分配,但它会阻止evaluate直接内联到for循环中,我认为Julia会在每次调用它时查找分派(尽管我们知道它没有改变)。最好将不同类型的选择移到默认参数中,这样函数体中的类型总是相同的。@MattB。啊,谢谢你。我没有注意到这种代码模式会引入类型不稳定性,但我现在可以看到。我已经更新了我的答案。现在去更新我自己的代码中我犯了这个错误的地方:-)代码有一个问题。您需要将FuncWithWeight参数化为eltype为w。否则,函数f不是专门用于w
的eltype(我试图编辑您的答案,但未被接受)。@Matthew同意。事实上,在查看LLVM IR时,我非常确定乘法是常数折叠的。因此,这里唯一的开销是checkbounds
——这是可以删除的。
function f(a::Vector, w::AbstractVector=Ones(size(a))
…