2015-11-13 61 views
7

版本:從朱莉婭V0.4起(我用0.5.0-dev的+ 433(2015年9月29日15:39 UTC))上演節目 - 傑克Bolewski的講話

參考Jake Bolewski: Staged programming in Julia

問題:看傑克斯Bolewski的關於StaticVec演講結束後我沒趕上例子背後的理念與length功能。

julia> type StaticVec{T,N} 
     vals::Vector{T} 
     end 

julia> StaticVec(T,vals...) = StaticVec{T,length(vals)}([vals...]) 
StaticVec{T,N} 

julia> v= StaticVec(Float64,1,2,3) 
StaticVec{Float64,3}([1.0,2.0,3.0]) 

非上演length

julia> function Base.length{T,N}(v::StaticVec{T,N}) 
     N 
     end 
length (generic function with 58 methods) 

julia> code_llvm(length, (StaticVec{Float64,3},)) 

define i64 @julia_length_21889(%jl_value_t*) { 
top: 
    ret i64 3 
} 

,並上演length版本

julia> @generated function Base.length{T,N}(v::StaticVec{T,N}) 
     :(N) 
     end 
length (generic function with 58 methods) 

julia> code_llvm(length, (StaticVec{Float64,3},)) 

define i64 @julia_length_21888(%jl_value_t*) { 
top: 
    ret i64 3 
} 

給出相同的LLVM代碼。

我想我明白舞臺編程背後的想法,但在這個特殊的例子中,我不明白演講者的意圖。任何人都可以向我解釋嗎?

回答

11

這個例子可能不是最好的選擇,因爲正如你指出的那樣,它根本不需要生成函數。 Jiahao Chen最近寫了一個blog post,這個例子用一個生成的函數來進行高效的數據平滑。下面是碼給他的類似位,通過剝離在前面M循環迭代和背面,從而避免在主循環體​​分支甚至進一步提高了效率:

immutable SavitzkyGolayFilter{M,N} end 

wrapL(i, n) = ifelse(1 ≤ i, i, i + n) 
wrapR(i, n) = ifelse(i ≤ n, i, i - n) 

@generated function smooth!{M,N}(
    ::Type{SavitzkyGolayFilter{M,N}}, 
    data::AbstractVector, 
    smoothed::AbstractVector, 
) 
    # compute filter coefficients from the Jacobian 
    J = Float64[(i-M-1)^(j-1) for i = 1:2M+1, j = 1:N+1] 
    e₁ = [1; zeros(N)] 
    C = J' \ e₁ 

    # generate code to evaluate filter on data matrix 
    pre = :(for i = 1:$M end) 
    main = :(for i = $(M+1):n-$M end) 
    post = :(for i = n-$(M-1):n end) 
    for loop in (pre, main, post) 
     body = loop.args[2].args 
     push!(body, :(x = $(C[M+1]) * data[i])) 
     for j = reverse(1:M) 
      idx = loop !== pre ? :(i-$j) : :(wrapL(i-$j,n)) 
      push!(body, :(x += $(C[M+1-j]) * data[$idx])) 
     end 
     for j = 1:M 
      idx = loop !== post ? :(i+$j) : :(wrapR(i+$j,n)) 
      push!(body, :(x += $(C[M+1+j]) * data[$idx])) 
     end 
     push!(body, :(smoothed[i] = x)) 
    end 
    quote 
     n = length(data) 
     n == length(smoothed) || throw(DimensionMismatch()) 
     @inbounds $pre; @inbounds $main; @inbounds $post 
     return smoothed 
    end 
end 

smooth{S<:SavitzkyGolayFilter,T}(::Type{S}, data::AbstractVector{T}) = 
    smooth!(S, data, Vector{typeof(1.0*one(T))}(length(data))) 

smooth(SavitzkyGolayFilter{3,4}, rand(1000))生成的代碼,例如,是以下內容:

n = length(data) 
n == length(smoothed) || throw(DimensionMismatch()) 
@inbounds for i = 1:3 
    x = 0.5670995670995674 * data[i] 
    x += 0.02164502164502159 * data[wrapL(i - 3, n)] 
    x += -0.1298701298701297 * data[wrapL(i - 2, n)] 
    x += 0.32467532467532445 * data[wrapL(i - 1, n)] 
    x += 0.32467532467532473 * data[i + 1] 
    x += -0.12987012987013022 * data[i + 2] 
    x += 0.021645021645021724 * data[i + 3] 
    smoothed[i] = x 
end 
@inbounds for i = 4:n-3 
    x = 0.5670995670995674 * data[i] 
    x += 0.02164502164502159 * data[i - 3] 
    x += -0.1298701298701297 * data[i - 2] 
    x += 0.32467532467532445 * data[i - 1] 
    x += 0.32467532467532473 * data[i + 1] 
    x += -0.12987012987013022 * data[i + 2] 
    x += 0.021645021645021724 * data[i + 3] 
    smoothed[i] = x 
end 
@inbounds for i = n-2:n 
    x = 0.5670995670995674 * data[i] 
    x += 0.02164502164502159 * data[i - 3] 
    x += -0.1298701298701297 * data[i - 2] 
    x += 0.32467532467532445 * data[i - 1] 
    x += 0.32467532467532473 * data[wrapR(i + 1, n)] 
    x += -0.12987012987013022 * data[wrapR(i + 2, n)] 
    x += 0.021645021645021724 * data[wrapR(i + 3, n)] 
    smoothed[i] = x 
end 
return smoothed 

正如您可能想象的那樣,這會生成非常高效的機器碼。我希望能稍微清理生成函數的概念。

+0

謝謝Stefan。雖然你的例子非常精細,我更喜歡文檔中的例子,但是你的答案已經證實了我的預測。 –