如何制作更强大的拉链/解压缩?

时间:2015-10-22 00:06:29

标签: julia

我有Array{Tuple{A, B}},我想将其解压缩/转置为Tuple{Array{A}, Array{B}}

typealias MyIndexType Tuple{Bool, Int}

function test(x::MyIndexType)
    # prepare for test data set.
    myArray = Array{Tuple{MyIndexType, Float64}}(0)
    push!(myArray, (x,1))
    push!(myArray, (x,1))
    push!(myArray, (x,1))

    # transform
    a, b = (zip(myArray...)...)
    [a...]
end

test((true, 1))

>>>
3-element Array{Tuple{Bool,Int64},1}:
(true,1)
(true,1)
(true,1)

但是,使用@code_warntype时,JIT无法提前推断出ab的类型。

Variables:
  x::Tuple{Bool,Int64}
  myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1}
  a::ANY
  b::ANY
  #s41::Int64

Body:
  begin  # In[47], line 6:
      myArray = (top(ccall))(:jl_alloc_array_1d,(top(apply_type))(Base.Array,Tuple{Tuple{Bool,Int64},Float64},1)::Type{Array{Tuple{Tuple{Bool,Int64},Float64},1}},(top(svec))(Base.Any,Base.Int)::SimpleVector,Array{Tuple{Tuple{Bool,Int64},Float64},1},0,0,0)::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 7:
      (Main.push!)(myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1},(top(tuple))(x::Tuple{Bool,Int64},1)::Tuple{Tuple{Bool,Int64},Int64})::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 8:
      (Main.push!)(myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1},(top(tuple))(x::Tuple{Bool,Int64},1)::Tuple{Tuple{Bool,Int64},Int64})::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 9:
      (Main.push!)(myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1},(top(tuple))(x::Tuple{Bool,Int64},1)::Tuple{Tuple{Bool,Int64},Int64})::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 10:
      GenSym(0) = (top(_apply))((top(getfield))(Main,:call)::F,top(tuple),(top(_apply))((top(getfield))(Main,:call)::F,Main.zip,myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1})::UNION{BASE.ZIP2{TUPLE{TUPLE{BOOL,INT64},FLOAT64},TUPLE{TUPLE{BOOL,INT64},FLOAT64}},TUPLE{TUPLE{BOOL,INT64},FLOAT64},ZIP{I,Z<:BASE.ABSTRACTZIPITERATOR}})::TUPLE
      #s41 = 1
      GenSym(4) = (Base.getfield)(GenSym(0),1)::ANY
      GenSym(5) = (Base.box)(Base.Int,(Base.add_int)(1,1)::ANY)::Int64
      a = GenSym(4)
      #s41 = GenSym(5)
      GenSym(6) = (Base.getfield)(GenSym(0),2)::ANY
      GenSym(7) = (Base.box)(Base.Int,(Base.add_int)(2,1)::ANY)::Int64
      b = GenSym(6)
      #s41 = GenSym(7) # In[47], line 11:
      return (top(_apply))((top(getfield))(Main,:call)::F,top(vect),a)::ANY
  end::ANY

有没有办法让zip知道结果类型?

更新

实际上有两个问题。

  1. 它认为a属于a::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}类型,但实际上属于a::TUPLE{FLOAT64,FLOAT64}

    类型
    function test{T}(x::T)
        A = Tuple{T, Int}[]
    
        for i in 1:3
            push!(A, (x, 1))
        end
    
        d = zip(A[1], A[2])
        a, b = d
        a
    end
    
    @code_warntype test(3.0)
    
    
    Variables:
      x::Float64
      A::Array{Tuple{Float64,Int64},1}
      d::Base.Zip2{Tuple{Float64,Int64},Tuple{Float64,Int64}}
      a::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
      b::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
      #s40::Tuple{Int64,Int64}
      #s41::Int64
      i::Int64
    
  2. 对于zip超过2个参数,请注意d有一个嵌套的zip2类型,我觉得这可能会给类型推断带来负担。

    function test{T}(x::T)
        A = Tuple{T, Int}[]
    
        for i in 1:3
            push!(A, (x, 1))
        end
    
        d = zip(A[1], A[2], A[3])
        a, b = d
        a
    end
    
    @code_warntype test(3.0)
    
    Variables:
      x::Float64
      A::Array{Tuple{Float64,Int64},1}
    
    
      d::Zip{Tuple{Float64,Int64},Base.Zip2{Tuple{Float64,Int64},Tuple{Float64,Int64}}}
      a::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
      b::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
      #s40::Tuple{Int64,Tuple{Int64,Int64}}
      #s41::Int64
      i::Int64
      ##c#7879::Tuple{Tuple{Float64,Int64}}
    
  3. 为什么我关心这种类型?

    编译以下示例的a,b = zip(A ...)需要10秒以上,速度似乎与A的长度有关。(Julia 0.4)

    const A = Tuple{Int, Int}[]
    
    for i = 1:200
        push!(A, (1, 1))
    end
    
    a, b = zip(A...)
    a
    

    我在这里打开了一个错误报告

1 个答案:

答案 0 :(得分:1)

我认为@code_warntype报告如果最终确定正确的类型,则无法推断它是不是一个问题。

我仍然想知道这是否是由于您的类型的复杂性。但它不是,如下面的代码所示(具有更简单的类型)。

请注意,您还可以简化zip表达式;而且您可能不需要将a转换为数组。

代码:

function test{T}(x::T)
    A = Tuple{T, Int}[]

    for i in 1:3
        push!(A, (x, 1))
    end

    a, b = zip(A...)
    a, b
end

julia> test(3)  # now returns a and b
((3,3,3),(2,2,2))   

julia> @code_warntype test(3)
Variables:
  x::Int64
  A::Array{Tuple{Int64,Int64},1}
  a::ANY
  b::ANY
  #s40::ANY
  #s41::Int64
  i::Int64