AxisKeys.jl icon indicating copy to clipboard operation
AxisKeys.jl copied to clipboard

vcat / hcat is broken on julia 1.10

Open takbal opened this issue 1 year ago • 5 comments

hcat and vcat seems to be in conflict with SparseArrays in julia-1.10, that is also pirating these Base calls now.

Works on 1.9.

julia> versioninfo()
Julia Version 1.10.0
Commit 3120989f39 (2023-12-25 18:01 UTC)
Build Info:

    Note: This is an unofficial build, please report bugs to the project
    responsible for this build and not to the Julia project unless you can
    reproduce the issue using official builds available at https://julialang.org/downloads

Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 16 × AMD Ryzen 7 1700 Eight-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, znver1)
  Threads: 24 on 16 virtual cores
Environment:
  JULIA_EDITOR = code

(@v1.10) pkg> add AxisKeys
julia> using AxisKeys

julia> a = wrapdims(zeros(2,2), foo = [1,2], bar = [1,2])
julia> b = wrapdims(zeros(2,2), foo = [1,2], bar = [1,2])
julia> [a ; b]

ERROR: MethodError: vcat(::KeyedArray{Float64, 2, NamedDimsArray{(:foo, :bar), Float64, 2, Matrix{Float64}}, Tuple{Vector{Int64}, Vector{Int64}}}, ::KeyedArray{Float64, 2, NamedDimsArray{(:foo, :bar), Float64, 2, Matrix{Float64}}, Tuple{Vector{Int64}, Vector{Int64}}}) is ambiguous.

Candidates:
  vcat(A::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, B::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, Cs::AbstractVecOrMat...)
    @ AxisKeys ~/.julia/packages/AxisKeys/QsNqy/src/functions.jl:147
  vcat(X1::Union{Number, AbstractVecOrMat{<:Number}}, X::Union{Number, AbstractVecOrMat{<:Number}}...)
    @ SparseArrays ~/software/julia-1.10.0/share/julia/stdlib/v1.10/SparseArrays/src/sparsevector.jl:1235
  vcat(A::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, B::AbstractVecOrMat, Cs::AbstractVecOrMat...)
    @ AxisKeys ~/.julia/packages/AxisKeys/QsNqy/src/functions.jl:147
  vcat(A::AbstractVecOrMat, B::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, Cs::AbstractVecOrMat...)
    @ AxisKeys ~/.julia/packages/AxisKeys/QsNqy/src/functions.jl:147

Possible fix, define
  vcat(::Union{KeyedArray{…}, KeyedArray{…}}, ::Union{KeyedArray{…}, KeyedArray{…}}, ::Vararg{AbstractVecOrMat{…}})

Stacktrace:
 [1] top-level scope
   @ REPL[7]:1
Some type information was truncated. Use `show(err)` to see complete types.

julia> [a b]

ERROR: MethodError: hcat(::KeyedArray{Float64, 2, NamedDimsArray{(:foo, :bar), Float64, 2, Matrix{Float64}}, Tuple{Vector{Int64}, Vector{Int64}}}, ::KeyedArray{Float64, 2, NamedDimsArray{(:foo, :bar), Float64, 2, Matrix{Float64}}, Tuple{Vector{Int64}, Vector{Int64}}}) is ambiguous.

Candidates:
  hcat(A::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, B::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, Cs::AbstractVecOrMat...)
    @ AxisKeys ~/.julia/packages/AxisKeys/QsNqy/src/functions.jl:155
  hcat(X1::Union{Number, AbstractVecOrMat{<:Number}}, X::Union{Number, AbstractVecOrMat{<:Number}}...)
    @ SparseArrays ~/software/julia-1.10.0/share/julia/stdlib/v1.10/SparseArrays/src/sparsevector.jl:1229
  hcat(A::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, B::AbstractVecOrMat, Cs::AbstractVecOrMat...)
    @ AxisKeys ~/.julia/packages/AxisKeys/QsNqy/src/functions.jl:155
  hcat(A::AbstractVecOrMat, B::Union{KeyedArray{T, 1, AT, RT}, KeyedArray{T, 2, AT, RT}} where {T, AT, RT}, Cs::AbstractVecOrMat...)
    @ AxisKeys ~/.julia/packages/AxisKeys/QsNqy/src/functions.jl:155

Possible fix, define
  hcat(::Union{KeyedArray{…}, KeyedArray{…}}, ::Union{KeyedArray{…}, KeyedArray{…}}, ::Vararg{AbstractVecOrMat{…}})

Stacktrace:
 [1] top-level scope
   @ REPL[8]:1
Some type information was truncated. Use `show(err)` to see complete types.

takbal avatar Jan 09 '24 13:01 takbal

Yeah, that's a known breaking change in Julia 1.10 unfortunately. https://github.com/JuliaLang/julia/issues/52386 https://github.com/JuliaSparse/SparseArrays.jl/issues/431

aplavin avatar Jan 09 '24 15:01 aplavin

I'm having the same issue unfortunately. While this is still pending, Is there any quick work around without downgrading julia?

jtackm avatar Mar 12 '24 14:03 jtackm

The new thing on 1.10 is methods with AbstractVecOrMat{<:Number} defined by SparseArrays. These amount to piracy of Base as it does not own any of those types. The nicest solution would be for those methods to be removed, but from https://github.com/JuliaSparse/SparseArrays.jl/issues/431 it looks like nobody has tried.

The alternative is to add ever more specific method here. There's already quite a list, in order for this package and NamedDims.jl to be able to be used together. Adding some versions with {<:Number} may solve this:

https://github.com/mcabbott/AxisKeys.jl/blob/master/src/functions.jl#L108-L113

Unfortunately I think the problem of many packages extending the same functions doesn't really have a satisfying solution, perhaps it's a flaw of multiple dispatch. The best I can think of would be first that Base uses similar(..., axes(x,1)) etc instead of size (which would also allow OffsetArrays, something like https://github.com/JuliaLang/julia/pull/37629, and https://github.com/JuliaLang/julia/pull/43552) and then this package return special axes (as in https://github.com/mcabbott/AxisKeys.jl/pull/6). Then perhaps no overload of vcat (nor *) would be needed, and the only tricky function would be similar.

mcabbott avatar Mar 12 '24 15:03 mcabbott

@jtackm in case you can modify the failing code, replacing [a ; b] with cat(a, b; dims=1) and [a b] with cat(a, b; dims=2) works for now.

takbal avatar Mar 16 '24 22:03 takbal

A workaround I found working reliably is:

Base.delete_method.(filter(
    m -> nameof(m.module) == :SparseArrays && m.sig == Tuple{typeof(vcat), Union{Number,AbstractVecOrMat{<:Number}}, Vararg{Union{Number,AbstractVecOrMat{<:Number}}}},
    methods(vcat)
))
Base.delete_method.(filter(
    m -> nameof(m.module) == :SparseArrays && m.sig == Tuple{typeof(hcat), Union{Number,AbstractVecOrMat{<:Number}}, Vararg{Union{Number,AbstractVecOrMat{<:Number}}}},
    methods(hcat)
))

Put this code into your script/code anywhere after package imports. It deletes those pirating methods defined in SparseArrays, getting rid of such ambiguities. At the same time, it doesn't interfere with vcat/hcat on actual sparse arrays – they continue returning sparse arrays.

aplavin avatar May 14 '24 19:05 aplavin

fwiw: This also arises when one loads the Optim package, which presumably loads SparseArrays.

NittanyLion avatar Jun 12 '25 19:06 NittanyLion

#169 fixed

aplavin avatar Jul 15 '25 22:07 aplavin