【问题标题】:Is there a way to swap columns in O(1) in Julia?有没有办法在 Julia 中交换 O(1) 中的列?
【发布时间】:2020-02-28 05:30:01
【问题描述】:

我请 Julia 做一些数值分析工作,并试图实现一个完整的枢轴 LU 分解(例如,试图获得一个尽可能稳定的 LU 分解)。我认为这样做的最佳方法是找到每列的最大值,然后按最大值的降序排列这些列。

有没有办法避免交换两列的每个元素,而是做一些像改变两个引用/指针这样的事情?

【问题讨论】:

  • 找到枢轴至少是 O(n²) 的操作,以新的顺序复制矩阵也是 O(n²),所以通过更有效地执行第二步不会获得太多方式。
  • 节省时间就是节省时间

标签: julia linear-algebra numerical-methods


【解决方案1】:

在 julia 中有 @view 宏,它允许您创建一个数组,它只是对另一个数组的引用,例如:


A = [1 2;3 4]
Aview = @view A[:,1] #view of the first column
Aview[1,1] = 10

julia> A
2×2 Array{Int64,2}:
 10  2
 3  4

话虽如此,当使用具体的数字类型(Float64、Int64 等)时,julia 使用直接表示数字类型的连续内存块。也就是说,julia 数字数组不是指针数组,数组的每个元素都是指向值的指针。如果数组的值可以用具体的二进制表示(例如结构数组)来表示,则使用指针数组。

我不是计算机科学专家,但我观察到,在进行数字运算时,最好将数据紧密打包,而不是使用大量指针。

另一种不同的情况是稀疏数组。稀疏数组的基本 julia 表示是一个索引数组和一个值数组。在这里你可以简单地交换索引而不是复制值

【讨论】:

  • 这个想法是所有算术都是一次在一个列上完成的,所以如果我有一个指向列开头的指针,我只是交换它们并且我没有内存访问问题,因为操作在列上,所有列都在连续内存上
  • 矩阵只是一个大向量,但具有相关的形状。矩阵的索引只是计算给定形状的值所在的偏移量。如果您想避免复制,您可以将索引存储在另一个数组中,并返回带有这些索引的修改后数组的视图。您以稍后索引速度较慢为代价来保存复制
  • 我可以只处理转置矩阵并将行视为列,但我想知道是否只实现了交换列
【解决方案2】:

跟进@longemen3000 的回答,您可以使用视图来交换列。例如:

julia> A = reshape(1:12, 3, 4)
3×4 reshape(::UnitRange{Int64}, 3, 4) with eltype Int64:
 1  4  7  10
 2  5  8  11
 3  6  9  12

julia> V = view(A, :, [3,2,4,1])
3×4 view(reshape(::UnitRange{Int64}, 3, 4), :, [3, 2, 4, 1]) with eltype Int64:
 7  4  10  1
 8  5  11  2
 9  6  12  3

也就是说,这是否是一个好的策略取决于访问模式。如果您将使用V 的元素一次或几次,则此view 策略是一个不错的策略。相反,如果您多次访问V 的元素,您最好在原地复制或移动值,因为这是您支付一次的价格,而在这里您每次访问值时都需要支付间接成本。

【讨论】:

    【解决方案3】:

    只是为了“完整性”,以防您真的想就地交换列,

    function swapcols!(X::AbstractMatrix, i::Integer, j::Integer)
        @inbounds for k = 1:size(X,1)
            X[k,i], X[k,j] = X[k,j], X[k,i]
        end
    end
    

    简单快捷。

    事实上,在小矩阵的单个基准测试中,这甚至比其他答案中提到的view 方法更快(视图并不总是免费的):

    julia> A = rand(1:10,4,4);
    
    julia> @btime view($A, :, $([3,2,1,4]));
      31.919 ns (3 allocations: 112 bytes)
    
    julia> @btime swapcols!($A, 1,3);
      8.107 ns (0 allocations: 0 bytes)
    

    【讨论】:

      猜你喜欢
      • 2023-03-08
      • 1970-01-01
      • 2021-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-01
      • 2018-11-02
      • 2017-07-30
      相关资源
      最近更新 更多