Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inference failure for concatenation #13665

Closed
afniedermayer opened this issue Oct 18, 2015 · 6 comments
Closed

Inference failure for concatenation #13665

afniedermayer opened this issue Oct 18, 2015 · 6 comments

Comments

@afniedermayer
Copy link
Contributor

function test()
    x=[1. 2.]
    y=3
    result = [y x]
    return result
end
@code_warntype test()

results in

Variables:
  x::Array{Float64,2}
  y::Int64
  result::ANY
  ##X#9661::Tuple{Int64,Array{Float64,2}}
  ####X#7774#9662::Tuple{Int64,Array{Float64,2}}
  ####T#7775#9663::TYPE{T}

Body:
  begin  # In[150], line 2:
      x = (Main.hcat)(1.0,2.0)::Array{Float64,2} # In[150], line 3:
      y = 3 # In[150], line 4:
      GenSym(1) = y::Int64
      GenSym(0) = x::Array{Float64,2}
      GenSym(2) = AST(:($(Expr(:lambda, Any[:(x::Any::ANY)], Any[Any[Any[:x,Any,0]],Any[],0,Any[]], :(begin  # abstractarray.jl, line 798:
        unless (Base.isa)(x,Base.AbstractArray)::ANY goto 0
        return (Base.eltype)(x)::ANY
        0: 
        return (Base.typeof)(x)::ANY
    end::ANY)))))
      ####T#7775#9663 = (Base.promote_type)((GenSym(2))(GenSym(1))::ANY,(GenSym(2))(GenSym(0))::ANY)::TYPE{T}
      result = (Base.cat_t)(2,####T#7775#9663::TYPE{T},GenSym(1),GenSym(0))::ANY # In[150], line 5:
      return result
  end::ANY

This issue looks related to, but different from #13254 since there is no T[a:b;] involved.

See also discussion at https://groups.google.com/forum/#!topic/julia-users/_lIVpV0e_WI

@GunnarFarneback
Copy link
Contributor

This is highly related to #13254. The common factor of failed type inference for concatenations is that they trickle down to the wonderfully general, but inherently type unstable, cat_t function. Concatenations that are caught by special cases of hcat, vcat, or hvcat fare better with respect to type inference.

@JeffBezanson
Copy link
Member

dup of #13254.

@afniedermayer
Copy link
Contributor Author

@JeffBezanson issue #13254 is a regression in 0.4, but this issue has already been there in 0.3, both for vcat or for hcat:

Base.return_types(hcat, (Int64, Array{Int64,2}))
Base.return_types(vcat, (Int64, Array{Int64,1}))

both return Any in Julia 0.3.

Coming from Matlab, it's natural to write [1;[2,3]] and [1 [2 3]], but this currently results in types not being inferred.

@afniedermayer
Copy link
Contributor Author

The reason why I'm mentioning this is that I've been working on some code that could fix this issue but not #13254 using generated functions, see https://gist.github.com/afniedermayer/947faadd362778d088d7
In case a patch is to arrive soon that fixes both issues, it would be unnecessary for me to keep working on the code.

@JeffBezanson
Copy link
Member

Ok. I think we should find a way to fix this without @generated.

@GregPlowman
Copy link
Contributor

This issue was referenced in a recent query on julia-users (https://groups.google.com/forum/#!topic/julia-users/ovCy89NDpJ0) where it was pointed out that b = [1;zeros(N-1)] was not type-stable.
I replied on that query with a possible workaround/fix but then a later post referenced this issue. I hope its OK to re-present here.

Now I don't fully understand the impact, but I think I was able to get a type-stable version of vcat with mixed scalar/vector arguments. Similarly for hcat.

Workaround was essentially to widen signatures of specialised vcat to allow mixed arguments and introduce full for Number. full(x::Number) acts as a sort of promote/convert to Vector for Numbers.

abstractarray.jl line 742
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
vcat(V::Union{Number,AbstractVector}...) = typed_vcat(promote_eltype(V...), V...)

abstractarray.jl line 745
function typed_vcat(T::Type, V::AbstractVector...)
function typed_vcat(T::Type, V::Union{Number,AbstractVector}...)

abstractarray.jl line 761
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
hcat(A::Union{Number,AbstractVector,AbstractMatrix}...) = typed_hcat(promote_eltype(A...), A...)

abstractarray.jl line 764
function typed_hcat(T::Type, A::AbstractVecOrMat...)
function typed_hcat(T::Type, A::Union{Number,AbstractVector,AbstractMatrix}...)

Base.full(x::Number) = [x]

As I don't know how to try these changes out directly, I copied method definitions and made signature changes (overwriting Base methods) and then tested with the following:

# test vcat
types = (Int64, Float64, Array{Int64,1}, Array{Float64,1})
argslist = [ (x,y) for x in types, y in types ]
for args in argslist
    ret_types = @eval Base.return_types(vcat, $args)
    T = ret_types[1]
    println("vcat", args, " --> ", T)
    @assert isleaftype(T)
    @assert T <: Vector
end
println()

# test hcat
types = (Int64, Float64, Array{Int64,1}, Array{Float64,1}, Array{Int64,2}, Array{Float64,2})
argslist = [ (x,y) for x in types, y in types ]
for args in argslist
    ret_types = @eval Base.return_types(hcat, $args)
    T = ret_types[1]
    println("hcat", args, " --> ", T)
    @assert isleaftype(T)
    @assert T <: Matrix
end
println()

All return types seemed to be inferred correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants