【问题标题】:Manually unrolling 3 nested loops (Julia)手动展开 3 个嵌套循环 (Julia)
【发布时间】:2021-07-12 21:02:56
【问题描述】:

这是Interpolating literals into each expression in an array using a for loop 的后续问题。在那个问题中,我想在循环中插入表达式的一维数组(向量)。使用公认的答案:

julia> array_of_expr = Any[:(A * 5), :(B * 6 * T)]

julia> arglist = [:A; :B; :T]
julia> test_input = [1e5, 1e1, 100]

julia> @eval begin
        function interpolate_1by1($(arglist...))
            result_array = similar($array_of_expr)
            $((quote
                result_array[$i] = $(array_of_expr[i])
            end for i in 1:length(array_of_expr))...)
            return result_array
        end
    end

julia> interpolate_all(test_input...)
2-element Array{Float64,1}:
 500000.0
 6000.0

使用the accepted answer,假设我现在有一个表达式向量数组:

args = [:A, :B, :C]
args_typed = [:($s::Float64) for s in args]
    
big_expr_array = Array{Vector{Expr}}(undef, 3, 4)
    
big_expr_array[1, :] = [[:(A+B), :(C/A)], [:(B+1), :(A+C)], [:(B%5)], [:(C+7)]]
big_expr_array[2, :] = [[:(A*B+C), :(B*C+A)], [:(C/6), :(C+C)], [:(3*C)], [:(A%2)]]
big_expr_array[3, :] = [[:(A*C), :(A*B)], [:(A-6), :(B+C/A)], [:(B+2)], [:(C%3)]]

并希望在给定一些参数的情况下评估所有表达式,而不会丢失数组的整体结构。在我看来,我必须遍历数组中的 i 行、j 列和 k 元素(表达式向量)。

我尝试通过两种方式修改上一个问题的已接受答案,这两种方式都会产生错误:

@eval begin
    function looped_eval1($(args_typed...))

        result = similar($big_expr_array)
        $( (quote 
            $( (quote 
                $( (quote
                        # i = row, j = vector, k = specific expression
                        result[$i, $j][$k] = $(big_expr_array[i, j][k])
                    end for k in 1:length(big_expr_array[i, j]))...
                 ) 
                end for j in 1:size(big_expr_array)[2])...
             )
            end for i in 1:size(big_expr_array)[1])...
         )
    end
end

这会抛出UndefRefError: access to undefined reference

第二:

@eval begin
    function looped_eval2($(args_typed...))
        
        result = similar($big_expr_array)
        $( (quote (quote (quote
                              # i = row, j = vector, k = specific expression
                              result[$i, $j][$k] = $(big_expr_array[i, j][k])
                          end for k in 1:length(big_expr_array[i, j]))... 
                   end for j in 1:size(big_expr_array)[2])...
            end for i in 1:size(big_expr_array)[1])...
         )
    
    end
end

这会抛出syntax: "..." expression outside call around In[130]:5

参数 A = 10、B = 20、C = 30 的示例期望结果:

big_expr_array[1, :] = [[30, 3], [21, 40], [0], [37]]
big_expr_array[2, :] = [[230, 610], [5, 60], [90], [0]]
big_expr_array[3, :] = [[300, 200], [4, 23], [22], [0]]

我应该如何编写手动循环展开以适应这些嵌套数组?或者,是否有更优雅的方式来实现对所有这些表达式的求值并保持相同的数组结构?

(代码也有可能正确分配给result——因为我卡在循环展开上,我不确定。)

【问题讨论】:

  • 你能解释一下for k in length(big_expr_array[i, j][k])这行吗,在定义之前你不能使用k
  • 我注意到 [k] 不应该在那里,我已经更正了错误并更新了原始问题,并进行了一些澄清和引发的实际错误。
  • 你可以看看Unrolled.jl

标签: arrays julia metaprogramming


【解决方案1】:

这里有一些工作:

@eval begin                                                                                                                                                      
    function looped_eval2($(args_typed...))                                                                                                                                                                                                                                                                                       
        result = similar($big_expr_array, Vector{Float64})                                                                                                           
        result .= [[]]                                                                                                                                               
        $( (quote                                                                                                                                                                          
                # i = row, j = vector, k = specific expression                                                                                                 
                push!(result[$i, $j], $(expr))                                                                                                                           
            end                                                                                                                                                                                                                                                                                                                       
            for i in 1:size(big_expr_array, 1)                                                                                                                           
            for j in 1:size(big_expr_array, 2)                                                                                                                           
            for expr in big_expr_array[i, j]                                                                                                                                  
            )...                                                                                                                                                                                    
        )                                                                                                                                                           
        result                                                                                                                                                   
    end                                                                                                                                                      
end

需要对您之前的工作进行一些修改:

  • 您必须键入 annotate 并初始化结果,否则当您尝试访问 result 的任何元素时会收到 UndefRefError;
  • 展开循环时,只需要一个引号,所有 3 个循环都在引号之外,然后计算生成的整个表达式列表;
  • 因为你的big_expr_array里面的所有向量的大小都不一样,结果的类型有点复杂(Matrix{Vector{Float}}),你必须在引号里面使用push!而不是直接定义价值。

结果如你所愿:

julia> looped_eval2(10., 20., 30.)                                                                                                                           
3×4 Matrix{Vector{Float64}}:                                                                                                                                  
    [30.0, 3.0]     [21.0, 40.0]  [0.0]   [37.0]                                                                                                                 
    [230.0, 610.0]  [5.0, 60.0]   [90.0]  [0.0]                                                                                                                  
    [300.0, 200.0]  [4.0, 23.0]   [22.0]  [0.0]

相同代码的更好 Julia 版本(根据 BenchmarkTools 稍好一些)将是:

@eval begin                                                                                                                                                      
    function looped_eval3($(args_typed...))                                                                                                                                                                                                                                                                                       
        result = map(_ -> Float64[], $big_expr_array)                                                                                                                
        $( (quote                                                                                                                                                            
                # i = row, j = vector, k = specific expression                                                                                                               
                push!(result[$i], $(expr))                                                                                                                               
            end                                                                                                                                                          
            for (i, expr_l) in enumerate(big_expr_array)                                                                                                                 
            for expr in expr_l                                                                                                                                           
            )...                                                                                                                                                      
        )                                                                                                                                                           
        result                                                                                                                                                   
    end                                                                                                                                                      
end

【讨论】:

  • 谢谢,语法“map(_ -> Float64 []”是什么意思,特别是下划线?我以前在Julia中没见过。我什至不知道怎么做在文档中搜索...搜索“_”没有任何用处。
  • 另外,是的,我必须看看实际代码中的性能是否还可以,其中向量可能很长(大约 100-500 个元素),因为它们是复杂化学网络的一部分。如果有问题,我将不得不看看我是否可以以某种方式预测它们的长度......谢谢!
  • _ 只是我不使用的变量的名称。 map 是一个函数,它将另一个函数应用于其第二个参数的所有值。此语句创建一个类似于 big_expr_array 的矩阵,其中充满了空浮点向量
  • 啊好的,我在这里找到了信息:discourse.julialang.org/t/usage-rules-for-bare-underscores/…谢谢
猜你喜欢
  • 2016-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-16
  • 2016-12-03
  • 1970-01-01
相关资源
最近更新 更多