簡體   English   中英

線性索引上三角矩陣

[英]Linear index upper triangular matrix

如果我有一個矩陣的上三角部分,在對角線上方偏移,存儲為線性數組,如何從數組的線性索引中提取矩陣元素的(i,j)索引?

例如,線性數組[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9是矩陣的存儲

0  a0  a1  a2  a3
0   0  a4  a5  a6
0   0   0  a7  a8
0   0   0   0  a9
0   0   0   0   0

我們想知道數組中的 (i,j) 索引對應於線性矩陣中的偏移量,而不需要遞歸。

例如,一個合適的結果k2ij(int k, int n) -> (int, int)會滿足

k2ij(k=0, n=5) = (0, 1)
k2ij(k=1, n=5) = (0, 2)
k2ij(k=2, n=5) = (0, 3)
k2ij(k=3, n=5) = (0, 4)
k2ij(k=4, n=5) = (1, 2)
k2ij(k=5, n=5) = (1, 3)
 [etc]

從線性索引到(i,j)索引的方程是

i = n - 2 - floor(sqrt(-8*k + 4*n*(n-1)-7)/2.0 - 0.5)
j = k + i + 1 - n*(n-1)/2 + (n-i)*((n-i)-1)/2

(i,j)索引到線性索引的逆運算是

k = (n*(n-1)/2) - (n-i)*((n-i)-1)/2 + j - i - 1

在 Python 中驗證:

from numpy import triu_indices, sqrt
n = 10
for k in range(n*(n-1)/2):
    i = n - 2 - int(sqrt(-8*k + 4*n*(n-1)-7)/2.0 - 0.5)
    j = k + i + 1 - n*(n-1)/2 + (n-i)*((n-i)-1)/2
    assert np.triu_indices(n, k=1)[0][k] == i
    assert np.triu_indices(n, k=1)[1][k] == j

for i in range(n):
    for j in range(i+1, n):
        k = (n*(n-1)/2) - (n-i)*((n-i)-1)/2 + j - i - 1
        assert triu_indices(n, k=1)[0][k] == i
        assert triu_indices(n, k=1)[1][k] == j

首先,讓我們以相反的順序對 a[k] 重新編號。 我們會得到:

0  a9  a8  a7  a6
0   0  a5  a4  a3
0   0   0  a2  a1
0   0   0   0  a0
0   0   0   0   0

那么 k2ij(k, n) 將變成 k2ij(n - k, n)。

現在,問題是,如何計算這個新矩陣中的 k2ij(k, n)。 序列 0, 2, 5, 9(對角元素的索引)對應三角形數(減 1 后):a[n - i, n + 1 - i] = Ti - 1. Ti = i * (i + 1 )/2,所以如果我們知道 Ti,很容易解出這個方程並得到 i(參見鏈接的維基文章中的公式,“三角根和三角形數的檢驗”部分)。 如果 k + 1 不完全是一個三角形數,公式仍然會給你有用的結果:四舍五入后,你會得到 i 的最高值,其中 Ti <= k,i 的這個值對應於行索引(從底部開始計數),其中 a[k] 位於。 要獲得該列(從右數),您應該簡單地計算 Ti 的值並減去它:j = k + 1 - Ti。 需要明確的是,這些並不是你的問題中的 i 和 j,你需要“翻轉”它們。

我沒有寫出確切的公式,但我希望你有這個想法,現在在執行一些無聊但簡單的計算后找到它會很簡單。

下面是matlab中的一個實現,可以很方便的移植到另一種語言,比如C++。 在這里,我們假設矩陣的大小為 m*m,ind 是線性數組中的索引。 唯一不同的是,在這里,我們逐列計算矩陣的下三角部分,這類似於您的情況(逐行計算上三角部分)。

function z= ind2lTra (ind, m)
  rvLinear = (m*(m-1))/2-ind;
  k = floor( (sqrt(1+8*rvLinear)-1)/2 );

  j= rvLinear - k*(k+1)/2;

  z=[m-j, m-(k+1)];

這是 k 的更有效的公式:

k = (2 * n - 3 - i) * i / 2 + j - 1

在蟒蛇中:

def k2ij(k, n):
    rows = 0
    for t, cols in enumerate(xrange(n - 1, -1, -1)):
        rows += cols
        if k in xrange(rows):
            return (t, n - (rows - k))
    return None

對於記錄,這是相同的函數,但使用基於 1 的索引,並且在 Julia 中:

function iuppert(k::Integer,n::Integer)
  i = n - 1 - floor(Int,sqrt(-8*k + 4*n*(n-1) + 1)/2 - 0.5)
  j = k + i + ( (n-i+1)*(n-i) - n*(n-1) )÷2
  return i, j
end

python中,最高效的方式是:

array_size= 3

# make indices using k argument if you want above the diagonal
u, v = np.triu_indices(n=array_size,k=1)

# assuming linear indices above the diagonal i.e. 0 means (0,1) and not (0,0)
linear_indices = [0,1]

ijs = [(i,j) for (i,j) in zip(u[linear_indices], v[linear_indices])]
ijs
#[(0, 1), (0, 2)]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM