【问题标题】:Julia function type instabilityJulia 函数类型不稳定性
【发布时间】:2017-12-05 22:26:25
【问题描述】:

对于如何在 Julia 中使函数类型稳定仍然有些困惑。 这是我的功能

function tran7(C::Array{Float64,1}, flux_up::Float64, D::Array{Float64,1},
    v::Array{Float64,1}, AFDW::Array{Float64,1}, VF::Array{Float64,1},
    VF_mid::Array{Float64,1})

    C_up = Float64[];
    flux = Array{Float64,1}(N+1); dC = Array{Float64, 1}(N)

    C_up = (flux_up + VF[1]*(D[1]/dx_aux[1] + (1-AFDW[1])*v[1])*C[1])/
    (VF[1]*(D[1]/dx_aux[1] + AFDW[1]*v[1]))

    flux = -VF.*D.*(vcat(C_up,C,C[N])[2:(N+2)] -
            vcat(C_up,C,C[N])[1:(N+1)])./dx_aux +
            VF.*v.*(AFDW.*vcat(C_up,C) + (1-AFDW).*vcat(C,C[N]))
    flux[1] = flux_up
    dC = -(flux[2:(N+1)] - flux[1:N])./(VF_mid.*dx)
    return dC
end

这是@code_warntype 结果

Variables:
  #self# <optimized out>
  C::Array{Float64,1}
  flux_up::Float64
  D::Array{Float64,1}
  v::Array{Float64,1}
  AFDW::Array{Float64,1}
  VF::Array{Float64,1}
  VF_mid::Array{Float64,1}
  #200::##200#203
  #201::##201#204
  #202::##202#205
  C_down <optimized out>
  C_up::ANY
  flux::ANY
  dC::ANY
  #temp#@_16::Core.MethodInstance
  #temp#@_17::ANY
  #temp#@_18::Core.MethodInstance
  #temp#@_19::ANY
  #temp#@_20 <optimized out>

Body:
  begin 
      C_up::ANY = $(Expr(:foreigncall, :(:jl_alloc_array_1d), 
Array{Float64,1}, svec(Any, Int64), Array{Float64,1}, 0, 0, 0)) # line 5:
      $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Float64,1}, svec(Any, Int64), Array{Float64,1}, 0, 0, 0)) # line 6:
  flux::ANY = (Array{Float64,1})((Main.N + 1)::ANY)::Array{Float64,1} # line 6:
  dC::ANY = (Array{Float64,1})(Main.N)::Array{Float64,1} # line 8:
  SSAValue(21) = (Base.arrayref)(VF::Array{Float64,1}, 1)::Float64
  SSAValue(20) = (((Base.arrayref)(D::Array{Float64,1}, 1)::Float64 / (Main.getindex)(Main.dx_aux, 1)::ANY)::ANY + (Base.mul_float)((Base.sub_float)((Base.sitofp)(Float64, 1)::Float64, (Base.arrayref)(AFDW::Array{Float64,1}, 1)::Float64)::Float64, (Base.arrayref)(v::Array{Float64,1}, 1)::Float64)::Float64)::ANY
  SSAValue(19) = (Base.arrayref)(C::Array{Float64,1}, 1)::Float64
  $(Expr(:inbounds, false))
  # meta: location operators.jl * 424
  SSAValue(22) = ((SSAValue(21) * SSAValue(20))::ANY * SSAValue(19))::ANY
  # meta: pop location
  $(Expr(:inbounds, :pop))
  C_up::ANY = ((flux_up::Float64 + SSAValue(22))::ANY / ((Base.arrayref)(VF::Array{Float64,1}, 1)::Float64 * (((Base.arrayref)(D::Array{Float64,1}, 1)::Float64 / (Main.getindex)(Main.dx_aux, 1)::ANY)::ANY + (Base.mul_float)((Base.arrayref)(AFDW::Array{Float64,1}, 1)::Float64, (Base.arrayref)(v::Array{Float64,1}, 1)::Float64)::Float64)::ANY)::ANY)::ANY # line 11:
  #200::##200#203 = $(Expr(:new, :(Main.##200#203)))
  SSAValue(1) = $(Expr(:invoke, MethodInstance for -(::Array{Float64,1}), :(Main.-), :(VF)))
  SSAValue(3) = (Main.vcat)(C_up::ANY, C::Array{Float64,1}, (Main.getindex)(C::Array{Float64,1}, Main.N)::ANY)::ANY
  SSAValue(4) = (Main.getindex)(SSAValue(3), (Main.colon)(2, (Main.N + 2)::ANY)::ANY)::ANY
  SSAValue(5) = (Main.vcat)(C_up::ANY, C::Array{Float64,1}, (Main.getindex)(C::Array{Float64,1}, Main.N)::ANY)::ANY
  SSAValue(6) = (Main.getindex)(SSAValue(5), (Main.colon)(1, (Main.N + 1)::ANY)::ANY)::ANY
  SSAValue(7) = (SSAValue(4) - SSAValue(6))::ANY
  SSAValue(33) = D::Array{Float64,1}
  SSAValue(34) = Main.dx_aux
  $(Expr(:inbounds, false))
  # meta: location broadcast.jl broadcast 434
  SSAValue(26) = SSAValue(7)
  SSAValue(27) = SSAValue(34)
  # meta: location broadcast.jl containertype 34
  SSAValue(25) = (Base.Broadcast.promote_containertype)(Array, (Base.Broadcast.promote_containertype)((Base.Broadcast._containertype)((Base.Broadcast.typeof)(SSAValue(26))::DataType)::ANY, (Base.Broadcast._containertype)((Base.Broadcast.typeof)(SSAValue(27))::DataType)::ANY)::ANY)::UNION{TYPE{ARRAY}, TYPE{BASE.SPARSEARRAYS.HIGHERORDERFNS.PROMOTETOSPARSE}}
  unless (SSAValue(25) isa Type{Array})::Bool goto 37
  #temp#@_16::Core.MethodInstance = MethodInstance for promote_containertype(::Type{Array}, ::Type{Array})
  goto 46
  37: 
  unless (SSAValue(25) isa Type{Base.SparseArrays.HigherOrderFns.PromoteToSparse})::Bool goto 41
  #temp#@_16::Core.MethodInstance = MethodInstance for promote_containertype(::Type{Array}, ::Type{Base.SparseArrays.HigherOrderFns.PromoteToSparse})
  goto 46
  41: 
  goto 43
  43: 
  #temp#@_17::ANY = (Base.Broadcast.promote_containertype)(Array, SSAValue(25))::UNION{TYPE{ARRAY}, TYPE{BASE.SPARSEARRAYS.HIGHERORDERFNS.PROMOTETOSPARSE}}
  goto 48
  46: 
  #temp#@_17::ANY = $(Expr(:invoke, :(#temp#@_16), :(Base.Broadcast.promote_containertype), Array, SSAValue(25)))
  48: 
  # meta: pop location
  # meta: pop location
  $(Expr(:inbounds, :pop))
  SSAValue(8) = (Base.Broadcast.broadcast_c)(#200::##200#203, #temp#@_17::ANY, SSAValue(1), SSAValue(33), SSAValue(7), SSAValue(34))::ANY
  #201::##201#204 = $(Expr(:new, :(Main.##201#204)))
  SSAValue(12) = ((Base.broadcast)(Main.*, AFDW::Array{Float64,1}, (Main.vcat)(C_up::ANY, C::Array{Float64,1})::ANY)::ANY + (Base.broadcast)(Main.*, $(Expr(:invoke, MethodInstance for -(::Int64, ::Array{Float64,1}), :(Main.-), 1, :(AFDW))), (Main.vcat)(C::Array{Float64,1}, (Main.getindex)(C::Array{Float64,1}, Main.N)::ANY)::ANY)::ANY)::ANY
  $(Expr(:inbounds, false))
  # meta: location broadcast.jl broadcast 434
  # meta: location broadcast.jl containertype 34
  SSAValue(28) = (Base.Broadcast.promote_containertype)(Array, (Base.Broadcast._containertype)((Base.Broadcast.typeof)(SSAValue(12))::DataType)::ANY)::UNION{TYPE{ARRAY}, TYPE{BASE.SPARSEARRAYS.HIGHERORDERFNS.PROMOTETOSPARSE}}
  unless (SSAValue(28) isa Type{Array})::Bool goto 62
  #temp#@_18::Core.MethodInstance = MethodInstance for promote_containertype(::Type{Array}, ::Type{Array})
  goto 71
  62: 
  unless (SSAValue(28) isa Type{Base.SparseArrays.HigherOrderFns.PromoteToSparse})::Bool goto 66
  #temp#@_18::Core.MethodInstance = MethodInstance for promote_containertype(::Type{Array}, ::Type{Base.SparseArrays.HigherOrderFns.PromoteToSparse})
  goto 71
  66: 
  goto 68
  68: 
  #temp#@_19::ANY = (Base.Broadcast.promote_containertype)(Array, SSAValue(28))::UNION{TYPE{ARRAY}, TYPE{BASE.SPARSEARRAYS.HIGHERORDERFNS.PROMOTETOSPARSE}}
  goto 73
  71: 
  #temp#@_19::ANY = $(Expr(:invoke, :(#temp#@_18), :(Base.Broadcast.promote_containertype), Array, SSAValue(28)))
  73: 
  # meta: pop location
  # meta: pop location
  $(Expr(:inbounds, :pop))
  SSAValue(13) = (Base.Broadcast.broadcast_c)(#201::##201#204, #temp#@_19::ANY, VF::Array{Float64,1}, v::Array{Float64,1}, SSAValue(12))::ANY
  flux::ANY = (SSAValue(8) + SSAValue(13))::ANY # line 14:
  (Main.setindex!)(flux::ANY, flux_up::Float64, 1)::ANY # line 15:
  #202::##202#205 = $(Expr(:new, :(Main.##202#205)))
  SSAValue(15) = -(((Main.getindex)(flux::ANY, (Main.colon)(2, (Main.N + 1)::ANY)::ANY)::ANY - (Main.getindex)(flux::ANY, (Main.colon)(1, Main.N)::ANY)::ANY)::ANY)::ANY
  SSAValue(35) = VF_mid::Array{Float64,1}
  SSAValue(36) = Main.dx
  $(Expr(:inbounds, false))
  # meta: location broadcast.jl broadcast 434
  SSAValue(32) = (Base.Broadcast.promote_containertype)((Base.Broadcast._containertype)((Base.Broadcast.typeof)(SSAValue(15))::DataType)::ANY, (Base.Broadcast.promote_containertype)(Array, (Base.Broadcast._containertype)((Base.Broadcast.typeof)(SSAValue(36))::DataType)::ANY)::UNION{TYPE{ARRAY}, TYPE{BASE.SPARSEARRAYS.HIGHERORDERFNS.PROMOTETOSPARSE}})::ANY
  # meta: pop location
  $(Expr(:inbounds, :pop))
  dC::ANY = (Base.Broadcast.broadcast_c)(#202::##202#205, SSAValue(32), SSAValue(15), SSAValue(35), SSAValue(36))::ANY # line 16:
  return dC::ANY
  end::ANY

我有几个问题。 (1)为什么预分配的变量(dCC_upflux)还有any的类型? (2)如果我在函数外部定义了一个参数(常量),例如这里的dx_aux,将其作为输入包含有没有好处? (3) 处理复杂的中间计算结果的最佳方法是什么?

【问题讨论】:

  • 您也可以发布@code_warntype 调用吗?
  • N在哪里定义?
  • 这不是 MWE,因为我们无法运行发布和复制的代码。如果您提供答案,您更有可能得到答案。
  • dx_aux 是用“const”声明的吗?

标签: julia


【解决方案1】:

C_upfluxdC 没有在函数头中定义,所以我假设它们是全局变量。全局变量总是可以改变类型,因为

x = 3
x = 2.0

在 REPL 中工作,因此这些函数不会专门针对全局变量的类型,因为担心类型错误。但是,如果它是一个常数,

const x = 3

然后编译器可以假设它不会改变,从而专注于类型并修复这个问题。注意数组的值是它们的引用,所以

const x = [3,4,5]
x[2] = 6

很好,因为x 的值只是引用,所以即使数组的内部值发生变化,它也不会改变。

(3) 处理复杂的中间计算结果的最佳方法是什么?

像你这里的缓存数组,或者带有缓存的可调用类型,或者......,这太宽泛了,无法很好地回答。

我会留下两个链接:

http://www.stochasticlifestyle.com/7-julia-gotchas-handle/

这描述了全局变量问题以及它发生的原因。而且:

https://github.com/JuliaLang/julia/issues/8870

建议一种新的语法:

x::Int = 3

以便非常量全局变量可以具有在进一步函数中推断的声明类型。这似乎不会成为 1.0,但它会是 1.x。

【讨论】:

  • 假设我有一个全局变量,我将它作为函数的参数传递,并在那里声明全局变量的类型。在这种情况下,在我的测试中,我是否在函数外部声明这个全局常量,或者是否将变量移动到函数中似乎并不重要。 N=1000function myfun(N::Int64) x = N+1 end
  • Julia 专门针对其参数编译函数。另一种思考方式是 Julia 的编译和优化单元是函数。每次调用函数时都会编译函数之外的任何内容,并且不是很优化。函数中的所有内容都经过优化。传递给函数的所有内容都经过优化。
猜你喜欢
  • 1970-01-01
  • 2023-02-06
  • 1970-01-01
  • 1970-01-01
  • 2018-09-08
  • 1970-01-01
  • 2022-12-12
  • 1970-01-01
  • 2021-07-11
相关资源
最近更新 更多