I wanted a scale! method that works for tridiagonal matrices and did the
following.
import Base.scale!
function scale!{T}(A::Tridiagonal{T}, x::T)
Base.scale!(A.dl, x)
Base.scale!(A.d, x)
Base.scale!(A.du, x)
return
end
Doing
methods(scale!)
gives the output
# 15 methods for generic function "scale!":
scale!{T<:Union(Complex{Float64},Float32,Complex{Float32},Float64)}(X::Array{T<:Union(Complex{Float64},Float32,Complex{Float32},Float64),N},s::T<:Union(Complex{Float64},Float32,Complex{Float32},Float64))
at linalg/dense.jl:11
...
scale!(X::AbstractArray{T,N},s::Number) at linalg/generic.jl:20
...
(A::CholmodSparse{T<:Union(Complex{Float64},Float32,Complex{Float32},Float64),Ti<:Union(Int64,Int32)},b::Array{T<:Union(Complex{Float64},Float32,Complex{Float32},Float64),1})
at linalg/cholmod.jl:907
scale!{T}(A::Tridiagonal{T},x::T) at none:2
however
A=Tridiagonal(rand(3),rand(4),rand(3))
4x4 Tridiagonal{Float64}:
0.342959 0.878001 0.0 0.0
0.0359927 0.481333 0.950373 0.0
0.0 0.764103 0.0200941 0.84859
0.0 0.0 0.220059 0.131956
scale!(A,2.0)
ERROR: indexing not defined for Tridiagonal{Float64}
in generic_scale! at linalg/generic.jl:16
in scale! at linalg/generic.jl:20
We can verify that Julia is not dispatching to the tridiagonal scale!
method:
which(scale!, (Tridiagonal{Float64},Float64))
scale!(X::AbstractArray{T,N},s::Number) at linalg/generic.jl:20
If I change the first line of the function definition to
function scale!(A::Tridiagonal,x)
then I get some ambiguity warnings:
Warning: New definition
scale!(Tridiagonal{T},Any) at none:2
is ambiguous with:
scale!(AbstractArray{T,N},Number) at linalg/generic.jl:20.
To fix, define
scale!(Tridiagonal{T},Number)
before the new definition.
Warning: New definition
scale!(Tridiagonal{T},Any) at none:2
is ambiguous with:
scale!(AbstractArray{T,2},AbstractArray{T,1}) at linalg/generic.jl:306.
To fix, define
scale!(Tridiagonal{T},AbstractArray{T,1})
before the new definition.
scale! (generic function with 15 methods)
Sure enough, defining
function scale!(A::Tridiagonal, x::Number)
Base.scale!(A.dl, x)
Base.scale!(A.d, x)
Base.scale!(A.du, x)
return
end
works fine. I am a bit mystified by this behaviour. Why was there no
warning for my first attempt?
Is there a problem in general with making a method "too specific"?