Qr of custom number type works but svd fails to find a method

Hi,

I’ve been playing around with implementing MyQuaternion type to demonstrate versatility of Julia’s type system to newcomers. I managed to get QR to work, but svd fails for some reason. Here is my implementation:

using Random
using LinearAlgebra
struct MyQuaternion{T} <: Number
    a :: T
    b :: T
    c :: T
    d :: T
end

Base.conj(a :: MyQuaternion{T}) where T = MyQuaternion{T}(a.a, -a.b, -a.c, -a.d)
Base.:+(a :: MyQuaternion{T}, b :: MyQuaternion{T}) where {T} = MyQuaternion{T}( a.a + b.a, a.b + b.b, a.c + b.c, a.d + b.d)
Base.:-(a :: MyQuaternion{T}) where {T} = MyQuaternion{T}(-a.a, -a.b, -a.c, -a.d)
Base.:-(a :: MyQuaternion{T}, b :: MyQuaternion{T}) where {T} = MyQuaternion{T}( a.a - b.a, a.b - b.b, a.c - b.c, a.d - b.d)
Base.:*(a :: MyQuaternion{T}, b :: MyQuaternion{T}) where {T} = MyQuaternion{T}( a.a * b.a - a.b * b.b - a.c * b.c - a.d * b.d,
                                                                                     a.a * b.b + a.b * b.a + a.c * b.d - a.d * b.c,
                                                                                     a.a * b.c + a.c * b.a + a.d * b.b - a.b * b.d,
                                                                                     a.a * b.d + a.d * b.a + a.b * b.c - a.c * b.b)
Base.:/(a :: MyQuaternion{T}, b :: T) where {T<:Number} = a * inv(b)
Base.:/(a :: MyQuaternion{T}, b :: MyQuaternion{T}) where {T} = a * inv(b)
Base.inv(a :: MyQuaternion{T}) where T = conj(a) / (a.a^2 + a.b^2 + a.c^2 + a.d^2)


Base.zero(::Type{MyQuaternion{T}}) where {T} = MyQuaternion{T}(zero(T),zero(T),zero(T),zero(T))
Random.rand(rng::AbstractRNG, ::Random.SamplerType{MyQuaternion{T}}) where T = MyQuaternion{T}(rand(T), rand(T), rand(T), rand(T))
Base.promote_rule(::Type{S}, ::Type{MyQuaternion{T}}) where {T, S} = MyQuaternion{promote_type(T, S)}
Base.convert(::Type{MyQuaternion{T}}, x::S) where {T, S<:Real} = MyQuaternion{promote_type(T, S)}(x, zero(promote_type(T, S)), zero(promote_type(T, S)), zero(promote_type(T, S)))
Base.real(x::MyQuaternion) = x.a
Base.abs2(x::MyQuaternion) = x.a^2 + x.b^2 + x.c^2 + x.d^2
Base.promote_rule(::Type{Bool}, ::Type{MyQuaternion{T}}) where T = MyQuaternion{T}

QR works just fine

A = rand(MyQuaternion{Float64}, 100, 100)
Q, R = qr(A)
Q * R == A # this is approximately true

However, svd F = svd(A) fails with the following error.

MethodError: no method matching svd!(::Array{MyQuaternion{Float64},2}; full=false, alg=LinearAlgebra.DivideAndConquer())
Closest candidates are:
  svd!(!Matched::LinearAlgebra.AbstractTriangular; kwargs...) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.4/LinearAlgebra/src/triangular.jl:2631
  svd!(!Matched::Union{DenseArray{T,2}, Base.ReinterpretArray{T,2,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray}, Base.ReshapedArray{T,2,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray}, SubArray{T,2,A,I,L} where L where I<:Tuple{Vararg{Union{Int64, AbstractRange{Int64}, Base.AbstractCartesianIndex},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, DenseArray}}; full, alg) where T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64} at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.4/LinearAlgebra/src/svd.jl:94
  svd!(!Matched::Union{DenseArray{T,2}, Base.ReinterpretArray{T,2,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray}, Base.ReshapedArray{T,2,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray}, SubArray{T,2,A,I,L} where L where I<:Tuple{Vararg{Union{Int64, AbstractRange{Int64}, Base.AbstractCartesianIndex},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, DenseArray}}, !Matched::Union{DenseArray{T,2}, Base.ReinterpretArray{T,2,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray}, Base.ReshapedArray{T,2,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray}, SubArray{T,2,A,I,L} where L where I<:Tuple{Vararg{Union{Int64, AbstractRange{Int64}, Base.AbstractCartesianIndex},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{Base.ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Union{Tuple{Vararg{Real,N} where N}, Tuple{AbstractUnitRange,Vararg{Any,N} where N}} where A<:DenseArray where N where T, DenseArray} where N where T, DenseArray}}) where T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64} at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.4/LinearAlgebra/src/svd.jl:365 got unsupported keyword arguments "full", "alg"
  ...

Stacktrace:
 [1] svd(::Array{MyQuaternion{Float64},2}; full::Bool, alg::LinearAlgebra.DivideAndConquer) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.4/LinearAlgebra/src/svd.jl:158
 [2] svd(::Array{MyQuaternion{Float64},2}) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.4/LinearAlgebra/src/svd.jl:158
 [3] top-level scope at In[20]:1

Any idea why svd fails? It’s weird to me that it seems to be failing at method lookup. I’m using version 1.4.2.

Thanks in advance!

I should add that when I was prototyping it, I got it to work a couple of times, during which svd printed something like “ignoring alg for generic SVD”. However, I have not been able to reproduce it since.

Try loading either GenericLinearAlgebra or GenericSVD

2 Likes