【问题标题】:Sparse matrices and type constraints in JuliaJulia 中的稀疏矩阵和类型约束
【发布时间】:2017-09-23 17:22:16
【问题描述】:

我对参数化方法在 Julia 中的工作方式感到困惑。我也希望参数是在这里使用的正确词。我已阅读有关方法的文档,但仍不清楚为什么会发生以下错误。如果我定义一个函数如下

function Bazinga{T<:Real}(mat ::Union{Array{T,2},SparseMatrixCSC})
    mat^4
end

然后运行

Penny = sparse(randn(10,10))
Bazinga(Penny)

我明白了

ERROR: MethodError: `Bazinga` has no method matching Bazinga(::SparseMatrixCSC{Float64,Int64})
Closest candidates are:
  Bazinga{T<:Real}(::Union{Array{T<:Real,2},SparseMatrixCSC{Tv,Ti<:Integer}})

但是Int64&lt;:Int 是真的,那么这里的问题是什么? 如果我将函数重新定义为

function Bazinga(mat ::Union{Array{Real,2},SparseMatrixCSC})
    mat^4
end

没有产生错误并且该功能有效。现在还有两个函数的方法

Bazinga(mat::Union{Array{Real,2},SparseMatrixCSC{Tv,Ti<:Integer}}) at none:2
Bazinga{T<:Real}(mat::Union{Array{T<:Real,2},SparseMatrixCSC{Tv,Ti<:Integer}}) at none:2

SparseMatrixCSC{Tv,Ti&lt;:Integer} 都在其中,但仅在第一种情况下会导致错误。 欢迎任何输入!

Edit1:为什么Array{Float64,1} &lt;:Array{Real,1} 是假的? Edit2:Edit1 中的问题由Arrays break string types in Julia 解决。但我认为它不能解释该方法会发生什么。或者至少我没有看到。

【问题讨论】:

  • Bazinga{T&lt;:Real}(mat::Union{Array{T,2},SparseMatrixCSC{T}) = mat^4 有效。似乎 Julia 喜欢 union 的所有元素都具有相同的参数“模板”。这可能是一个已知问题,熟悉它的人会回答。
  • 很可能,上述问题是因为 Union 选择了 SparseMatrixCSC 分支,然后由于 T 未使用,它无法填充参数 T 并确定与调用匹配的方法。
  • @Dan Getz 这听起来可能是原因。我使用您上面的建议来修复我的代码,非常感谢!我想给你和@Gnimuc K.,学分,但我怀疑有办法做到这一点

标签: methods types julia


【解决方案1】:

我不太清楚背后的原因,但使用 TypeVar 可能是您的用例的解决方法:

T = TypeVar(:T, Union{}, Real, false)

function Bazinga(mat::Union{Array{T,2},SparseMatrixCSC})
    mat^4
end

julia> Bazinga(sparse(randn(2,2)))
2x2 sparse matrix with 4 Float64 entries:
    [1, 1]  =  0.840151
    [2, 1]  =  -0.503551
    [1, 2]  =  -0.437787
    [2, 2]  =  1.28652

julia> Bazinga(randn(2,2))
2x2 Array{Float64,2}:
 0.203916   -0.261589 
 0.0107211  -0.0137373

更新:

经过一番调查,我发现解决这个问题的“规范”方法是定义一个typealias

typealias RealMatrix{T<:Real} Array{T, 2}

function Bazinga(mat::Union{RealMatrix, SparseMatrixCSC})
    mat^4
end

我猜原因是 Julia 在不知道所有参数类型到底是什么的情况下无法完成方法匹配任务。这是另一个例子:

Foo{R<:Real,C<:Complex}(x::Union{Array{R}, SparseMatrixCSC{C}}) = x

Foo(sparse([1+im 2; 3 4]))Foo(rand(2,2)) 都不起作用。所以编写参数联合方法的正确方法是通过typealias约束那些不同的参数:

julia> typealias Bar{T<:Real} Array{T,2}
Array{T<:Real,2}

julia> typealias Baz{T<:Complex} SparseMatrixCSC{T}
SparseMatrixCSC{T<:Complex{T<:Real},Ti<:Integer}

julia> Foo(x::Union{Bar, Baz}) = x
Foo (generic function with 1 method)

julia> Foo(rand(2,2))
2x2 Array{Float64,2}:
 0.000739447  0.713386
 0.32024      0.705593

julia> Foo(sparse([1+im; 2im]))
2x1 sparse matrix with 2 Complex{Int64} entries:
    [1, 1]  =  1+1im
    [2, 1]  =  0+2im  

如果联合的参数类型有相同的类型参数T,我们也可以使用typealias,如下:

julia> typealias MyUnion{T,N<:Integer} Union{Array{T,2}, SparseMatrixCSC{T,N}}
Union{Array{T,2},SparseMatrixCSC{T,N<:Integer}}

julia> Foo{T<:Real}(x::MyUnion{T}) = x
Foo (generic function with 1 method)

julia> Foo(rand(2,2))
2x2 Array{Float64,2}:
 0.0172915  0.587518  
 0.234148   0.00543953

julia> Foo(rand(2))
ERROR: MethodError: `Foo` has no method matching Foo(::Array{Float64,1})

julia> Foo(sparse(rand(2)))
2x1 sparse matrix with 2 Float64 entries:
    [1, 1]  =  0.900029
    [2, 1]  =  0.0634815

julia> Foo(sparse(rand(2,2)))
2x2 sparse matrix with 4 Float64 entries:
    [1, 1]  =  0.592632
    [2, 1]  =  0.066563
    [1, 2]  =  0.805307
    [2, 2]  =  0.923422

julia> Foo(rand(2,2))
2x2 Array{Float64,2}:
 0.167078  0.673194
 0.681418  0.316017

更新 2:

在 Julia-v0.6+ 中,不需要定义类型别名:

function Bazinga(mat::Union{Array{<:Real,2},SparseMatrixCSC})
    mat^4
end

详情请咨询this answer

【讨论】:

  • @olga.bio 实际上,typealias 是推荐的方式,请参阅上面的更新。
  • 非常感谢您的详细回复!这澄清了问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 2018-01-19
相关资源
最近更新 更多