如果我有一个矩阵的上三角形部分,在对角线上方偏移,存储为线性数组,那么如何从数组的线性索引中提取矩阵元素的(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]
答案 0 :(得分:33)
从线性索引到(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
答案 1 :(得分:3)
首先,让我们以相反的顺序重新编号[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(对角元素的索引)对应于triangular numbers(减去1之后):a [n - i,n + 1 - i] = Ti - 1. Ti = i *( i + 1)/ 2,所以如果我们知道Ti,那么很容易解决这个等式并得到i(参见链接的wiki文章中的公式,&#34;三角形根和三角数的测试&#34; )。如果k + 1不是一个三角形数字,公式仍会给你有用的结果:在将其向下舍入后,你将获得i的最高值,其中Ti <= k,这个值为i对应于行索引(从底部开始计数),其中a [k]位于其中。要获得列(从右计算),您应该简单地计算Ti的值并减去它:j = k + 1 - Ti。要明确的是,这些并不是你和你的问题,你需要&#34;翻转&#34;它们。
我没有写出确切的公式,但我希望你有了这个想法,现在在执行一些无聊但简单的计算之后找到它是微不足道的。
答案 2 :(得分:3)
以下是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)];
答案 3 :(得分:1)
在python中:
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
答案 4 :(得分:0)
对于记录,这是相同的功能,但使用基于一的索引,并且在 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