4
votes

I'm creating a custom matrix library by extending the functionality present in the LinearAlgebra module. I have been doing this by creating custom structs in a custom MyLinearAlgebra module that directly imports the default Linear Algebra structs and overrides many of the common LA functionalities. My question is specifically about how to override the backslash function. Here is my "MyLinearAlgebra.jl":

module MyLinearAlgebra

import LinearAlgebra
import Base: getindex, setindex!, size

export
# Types
LocalMatrix,
SolutionVector,
# Functions
lp_error!,
lp_norm,
true_size

include("SolutionVector.jl")
include("LocalMatrix.jl")

end

Focusing solely on LocalMatrix.jl now, I have:

"""
    struct LocalMatrix{T} <: AbstractMatrix{T}
Block diagonal structure for local matrix. `A[:,:,iS,iK]` is a block matrix for
state iS and element iK
"""
struct LocalMatrix{T} <: AbstractMatrix{T}
    data::Array{T,4}
    factorizations::Array{Any,2}

    function LocalMatrix(data::Array{T,4}) where {T}
        new{T}(data,Array{Any}(undef, size(data,3), size(data,4)))
    end
end

# [... a lot of things that are already working including: ldiv!]

"""
    ldiv!(A::LocalMatrix, x::SolutionVector)
In-place linear solve A\\x using block-diagonal LU factorizations. Compute this
block-diagonal factorization if not yet computed.
"""
function LinearAlgebra.ldiv!(A::LocalMatrix, x::SolutionVector)
    println("my ldiv! works fine")
    x
end
    
# [ ... and yet this does not work ]
"""
    A::LocalMatrix \\ x::SolutionVector
Linear solve A\\x using block-diagonal LU factorizations. Compute this
block-diagonal factorization if not yet computed.
"""
function (\)(A::LocalMatrix, x::SolutionVector)
    println("my \\ never prints out in any tests")
    (m,n,ns,ne) = size(A.data)
    (nx,nsx,nex) = size(x.data)
    @assert n == nx && ne == nex && m == n
    b = deepcopy(x)
    LinearAlgebra.ldiv!(A, b)
end

In my tests, I can use the ldiv! function exactly as expected, but I cannot use the \ function - it simply uses some standard implementation written somewhere else. I believe this is presumably because my backslash function is not qualified as the LinearAlgebra backslash function, but I'm not sure. Trying to qualify the function as LinearAlgebra.(\)(A::LocalMatrix, x::SolutionVector) fails with a syntax error invalid function name. Is there another way to do this, or am I missing something more fundamental about modules here?

1
You would need to use the signature LinearAlgebra.:\(x, y) to avoid the invalid function name error. However, even doing this I am still not able to override the default behaviour (which is why this is a comment not an answer) - Colin T Bowers
This is strange - it works for me. - Bogumił Kamiński
@BogumiłKamiński Ah! My fault. I'd reversed the order of the arguments in my test code and was at work so didn't have time to work out what the resulting error meant :-) - Colin T Bowers

1 Answers

3
votes

\ is defined in Base, so:

julia> "a" \ "b"
ERROR: MethodError: no method matching adjoint(::String)

julia> Base.:\(::String, ::String) = "hello"

julia> "a" \ "b"
"hello"

However, as it is imported to LinearAlgebra the following also works for me (I am using a fresh session):

julia> using LinearAlgebra

julia> "a" \ "b"
ERROR: MethodError: no method matching adjoint(::String)

julia> LinearAlgebra.:\(::String, ::String) = "hello"

julia> "a" \ "b"
"hello"

as Julia will add a method to the same function (defined in Base).