[英]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.