numpy 线性指数上三角矩阵

clj7thdc  于 2022-12-13  发布在  其他
关注(0)|答案(7)|浏览(125)

如果我有一个矩阵的上三角形部分,偏移在对角线之上,存储为一个线性数组,如何从数组的线性索引中提取矩阵元素的(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]
qhhrdooz

qhhrdooz1#

从线性折射率到(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
nxowjjhe

nxowjjhe2#

首先,让我们以相反的顺序对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

那么k2 ij(k,n)将变成k2 ij(n-k,n)。
现在的问题是,如何计算这个新矩阵中的k2 ij(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文章中的公式,“三角形数的三角形根和检验”部分)。如果k + 1不完全是三角形数,这个公式仍然会给予你有用的结果:在向下取整之后,你会得到i的最大值,对于Ti〈= k,这个i的值对应于a[k]所在的行索引(从底部开始计数)。要得到列(从右边开始计数),你只需计算Ti的值并减去它:j = k + 1 - Ti。要清楚的是,这些并不完全是你问题中的i和j,你需要“翻转”它们。
我没有写出确切的公式,但我希望你已经明白了,现在在进行一些枯燥但简单的计算后,找到它将是微不足道的。

epggiuax

epggiuax3#

下面是一个在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)];
hmae6n7t

hmae6n7t4#

对于记录,这是相同的函数,但使用基于一的索引,并且在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
yzxexxkh

yzxexxkh5#

下面是一个更有效的k公式:

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

j8yoct9x6#

在Python 2中:

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
bvjxkvbb

bvjxkvbb7#

中,最有效的办法就是:

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)]

相关问题