【问题标题】:Type stability for a function involving case distinctions涉及案例区分的函数的类型稳定性
【发布时间】:2017-11-17 22:25:49
【问题描述】:

我正在编写一个计算重心插值公式权重的函数。忽略类型稳定性,这很容易:

function baryweights(x)
    n = length(x)
    if n == 1; return [1.0]; end # This is obviously not type stable

    xmin,xmax = extrema(x)
    x *= 4/(xmax-xmin)
    # ^ Multiply by capacity of interval to avoid overflow
    return [
        1/prod(x[i]-x[j] for j in 1:n if j != i)
        for i = 1:n
    ]
end

类型稳定性的问题是计算出n > 1 情况下的返回类型,以便我可以在n == 1 情况下返回正确类型的数组。有没有简单的技巧可以实现这一点?

【问题讨论】:

  • 预期结果是什么?因为如果我调用baryweights([1,2,3]) 意味着参数是Array{Int} 结果是Array{Float64}!你指的真的是网上的问题吗?
  • 是的,这是需要的。我希望返回类型是 n > 1 案例返回的任何值,但对于 n = 1 的任何值都应该是这样,包括 n == 1
  • 但是什么是用例?我尝试了复数,但它不适用于 extrema 函数。您能否举一些类型与预期不同的示例?
  • Ints 作为输入将是我想要支持的情况。一旦我解决了极值问题,也许还有复数。

标签: julia generic-programming


【解决方案1】:

我不确定我是否了解您的计划。但也许这样的事情会有所帮助? ->

baryone(t::T) where T<:Real = [1.]
baryone(t::T) where T<:Complex = [1im]  # or whatever you like here

function baryweights(x::Array{T,1}) where T<:Number
    n = length(x)
    n == 1 && return baryone(x[1])
    xmin,xmax = extrema(x)  # don't forget fix extrema for complex! :)
    x *= 4/(xmax-xmin)
    # ^ Multiply by capacity of interval to avoid overflow
    return [
        1/prod(x[i]-x[j] for j in 1:n if j != i)
        for i = 1:n
    ]
end

警告:我还是新手!如果我尝试@code_warntype baryweights([1]),我只会看到很多警告。 (如果我避免打电话给baryone)。比如n就是Any!!

编辑: 我asked on discourse 现在看到@code_warn 如果我们使用另一个变量(y)返回更好的结果:

function baryweights(x::Array{T,1}) where T<:Number
    n = length(x)
    n == 1 && return baryone(x[1])
    xmin,xmax = extrema(x)  # don't forget fix extrema for complex! :)
    let y = x * 4/(xmax-xmin)
        # ^ Multiply by capacity of interval to avoid overflow
        return [
            1/prod(y[i]-y[j] for j in 1:n if j != i)
            for i = 1:n
        ]
    end
end

Edit2:我添加了let 以避免y 成为Core.Boxed

【讨论】:

  • 非常感谢您对这个问题的关注!我不知道闭包引入了另一种类型的不稳定性,而您指出 let 解决方法为我节省了大量的谷歌搜索时间!
  • 现在至于我想要实现的目标:我想确保 n == 1 案例返回与其他案例完全相同的类型,无论输入类型是什么。如果要考虑一组有限且已知的案例,您的解决方法是可行的,但即便如此,我也必须将它们全部列出,这很乏味、容易出错且难以维护。我的解决方案的诀窍是,我可以保证返回类型是相同的,无论你将什么类型输入到我的函数中。
【解决方案2】:

只需在一个虚拟参数上递归调用函数:

function baryweights(x)
    n = length(x)
    if n == 1
        T = eltype(baryweights(zeros(eltype(x),2)))
        return [one(T)]
    end

    xmin,xmax = extrema(x)
    let x = 4/(xmax-xmin) * x
        # ^ Multiply by capacity of interval to avoid overflow,
        #   and wrap in let to avoid another source of type instability
        #   (https://github.com/JuliaLang/julia/issues/15276)
        return [
            1/prod(x[i]-x[j] for j in 1:n if j != i)
            for i = 1:n
        ]
    end
end

【讨论】:

  • 你测试了吗?你的意思可能是T = eltype(baryweights(zeros(eltype(x),2)))
  • 对。不,我又一次没能看到所有树木后面的森林,忘记测试了。我会调查的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多