Julia或R:通过最少的非对角元素创建对称矩阵

时间:2019-03-22 22:42:25

标签: r matrix julia symmetric

这是一个复杂的问题。例如,我在R中有一个任意的正方形矩阵(也可以在Julia中)

> set.seed(420)
> A <- matrix(runif(16),nrow = 4,byrow = T)
> A
          [,1]      [,2]      [,3]      [,4]
[1,] 0.6055390 0.9702770 0.1744545 0.4757888
[2,] 0.7244812 0.8761027 0.3775037 0.6409362
[3,] 0.6546772 0.5062158 0.3033477 0.7162497
[4,] 0.2905202 0.1962252 0.3225786 0.8404279

我想将此矩阵转换为对称矩阵,以使对角线元素始终是A矩阵的2个相应对角线元素中的最小值。在上述情况下,结果必须为:

          [,1]      [,2]      [,3]      [,4]
[1,] 0.6055390 0.7244812 0.1744545 0.2905202
[2,] 0.7244812 0.8761027 0.3775037 0.1962252
[3,] 0.1744545 0.3775037 0.3033477 0.3225786
[4,] 0.2905202 0.1962252 0.3225786 0.8404279

将是一种在Julia和/或R中对其进行编程的高效且不费时的方法。必须适用于任何种类的方阵。

2 个答案:

答案 0 :(得分:2)

可能最好的方法是使用Rcpp进行几个for循环,但是您也可以尝试一下:

idx <- A <= t(A)
A * idx + t(A) * (1L - idx)

修改

基本R解决方案在时间和内存方面都是低效的。如果您需要速度和/或内存,请使用Rcpp函数,使矩阵对称。一个修改它,另一个返回一个副本。

library(Rcpp)

cppFunction('
void inplaceSymmetric(NumericMatrix A) {
  for (int i = 1; i < A.nrow(); ++i)
    for (int j = 0; j < i; ++j)
      if (A(i, j) < A(j, i)) 
        A(j, i) = A(i, j);
      else 
        A(i, j) = A(j, i);
}')

cppFunction('
NumericMatrix copySymmetric(NumericMatrix A) {
  NumericMatrix C = clone(A);
  for (int i = 1; i < A.nrow(); ++i)
    for (int j = 0; j < i; ++j)
      if (A(i, j) < A(j, i))
        C(j, i) = C(i, j);
      else
        C(i, j) = C(j, i);
  return C;
}')

答案 1 :(得分:2)

在朱莉娅,单线是

B = [min(A[i,j], A[j,i]) for i in axes(A, 1), j in axes(A, 2)]

但是,这可以完成所需工作的两倍。以下方法效率更高,可以就地修改原始矩阵,并且如果矩阵不是正方形,则会生成一条不错的错误消息:

function symmetrize_min!(A::AbstractMatrix)
    ax1 = axes(A, 1)
    axes(A, 2) == ax1 || error("A must be square")
    for j in ax1
        for i in j+1:last(ax1)
            A[i,j] = A[j,i] = min(A[i,j], A[j,i])
        end
    end
    return A
end

在Julia中,有一项约定,函数修改其参数以!结尾,作为对用户的警告。如果您不希望它修改A,则可以在调用之前copy(A)或进行一些小的更改:

function symmetrize_min(A::AbstractMatrix)
    ax1 = axes(A, 1)
    axes(A, 2) == ax1 || error("A must be square")
    B = similar(A)
    for j in ax1
        B[j,j] = A[j,j]
        for i in j+1:last(ax1)
            B[i,j] = B[j,i] = min(A[i,j], A[j,i])
        end
    end
    return B
end

在Julia中,您应该拥抱循环-循环很快。而且由于它们易于编写,看似复杂的问题也变得简单。