Yes, this seems odd. I think it's a bug. First, this also works:
function scale!{T<:Number}(A::Tridiagonal{T}, x::T)
Base.scale!(A.dl, x)
Base.scale!(A.d, x)
Base.scale!(A.du, x)
return
end
and is probably what you want as T needs to be a number for this to make
sense. Still:
I tried reproducing this with another function, which then gives the
expected ambiguity warning:
julia> f{T,N}(X::AbstractArray{T,N},s::Number) = 1
f (generic function with 1 method)
julia> f{T}(X::Tridiagonal{T},s::T) = 1
Warning: New definition
f(Tridiagonal{T},T) at none:1
is ambiguous with:
f(AbstractArray{T,N},Number) at none:1.
To fix, define
f(Tridiagonal{_<:Number},_<:Number)
before the new definition.
f (generic function with 2 methods)
julia> f{T<:Number}(X::Tridiagonal{T},s::T) = 1
f (generic function with 3 methods)
I think you're right, the scale! definition as you tried should give an
ambiguity warning but it doesn't. A bug.
Then trying changing the order of above definitions does not give an
ambiguity warning either. I would have thought that ambiguities should
be commutative?
julia> f{T}(X::Tridiagonal{T},s::T) = 1
f (generic function with 1 method)
julia> A=Tridiagonal(rand(3),rand(4),rand(3));
julia> f(A, 1.)
1
julia> f{T,N}(X::AbstractArray{T,N},s::Number) = 2
f (generic function with 2 methods)
julia> f(A, 1.)
1
julia> f(rand(3,3), 1.)
2
julia> f{T<:Number}(X::Tridiagonal{T},s::T) = 3
f (generic function with 3 methods)
julia> f(A, 1.)
3
On Tue, 2014-07-01 at 06:46, [email protected] wrote:
> 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"?