web-dev-qa-db-fra.com

Matrice triangulaire supérieure à index linéaire

Si j'ai la partie triangulaire supérieure d'une matrice, décalée au-dessus de la diagonale, stockée sous forme de tableau linéaire, comment les indices (i,j) D'un élément de matrice peuvent-ils être extraits de l'index linéaire du tableau?

Par exemple, le tableau linéaire [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 Est le stockage de la matrice

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

Et nous voulons connaître l'indice (i, j) dans le tableau correspondant à un décalage dans la matrice linéaire, sans récursivité.

Un résultat approprié, k2ij(int k, int n) -> (int, int) satisferait, par exemple

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]
34
Robert T. McGibbon

Les équations allant de l'indice linéaire à (i,j) index sont

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

L'opération inverse, de (i,j) index à index linéaire est

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

Vérifiez dans Python avec:

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
40
Robert T. McGibbon

Tout d'abord, renumérotons un [k] dans l'ordre inverse. Nous aurons:

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

Alors k2ij (k, n) deviendra k2ij (n - k, n).

Maintenant, la question est de savoir comment calculer k2ij (k, n) dans cette nouvelle matrice. La séquence 0, 2, 5, 9 (indices des éléments diagonaux) correspond à nombres triangulaires (après soustraction de 1): a [n - i, n + 1 - i] = Ti - 1. Ti = i * (i + 1)/2, donc si nous connaissons Ti, il est facile de résoudre cette équation et d'obtenir i (voir la formule dans l'article wiki lié, section "Racines triangulaires et tests pour les nombres triangulaires"). Si k + 1 n'est pas exactement un nombre triangulaire, la formule vous donnera toujours le résultat utile: après l'avoir arrondi, vous obtiendrez la valeur la plus élevée de i, pour laquelle Ti <= k, cette valeur de i correspond à la index de ligne (en partant du bas), dans lequel se trouve un [k]. Pour obtenir la colonne (en partant de la droite), vous devez simplement calculer la valeur de Ti et la soustraire: j = k + 1 - Ti. Pour être clair, ce ne sont pas exactement i et j de votre problème, vous devez les "retourner".

Je n'ai pas écrit la formule exacte, mais j'espère que vous avez eu l'idée, et il sera désormais trivial de la trouver après avoir effectué des calculs ennuyeux mais simples.

5
Mikhail Maltsev

Voici une implémentation dans matlab, qui peut être facilement transférée dans un autre langage, comme C++. Ici, nous supposons que la matrice a une taille m * m, ind est l'indice dans le tableau linéaire. La seule chose différente est qu'ici, nous comptons la partie triangulaire inférieure de la matrice colonne par colonne, ce qui est analogue à votre cas (en comptant la partie triangulaire supérieure ligne par ligne).

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
study

En 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
1
smac89