Question: étant donné un nuplet d’index, retourne son ordre dans les index triangulaires supérieurs. Voici un exemple:
Supposons que nous ayons une matrice carrée A de forme (3, 3).
A a 6 indices triangulaires supérieurs, à savoir, (0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2).
Maintenant, je connais un élément à l'index (1, 2), qui est un index qui appartient à la partie triangulaire supérieure de A. Je voudrais renvoyer 4 (ce qui signifie que c'est le 5ème élément de tous les indices triangulaires supérieurs.)
Des idées sur la façon de faire cela en général?
Meilleur, Zhihao
On peut écrire la formule explicite:
def utr_idx(N, i, j):
return (2*N+1-i)*i//2 + j-i
Démo:
>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123
Pour une matrice n × n , le (i, j) - ème élément du triangle supérieur est le i × (2 × n-i + 1)/2 + ji - ème élément de la matrice.
Nous pouvons également faire le calcul à l’inverse et obtenir l’élément (i, j) pour le k - ème élément avec:
i = ⌊ (-√ ((2n + 1)2-8k) + 2n + 1)/2⌋ et j = k + i-i × (2 × n-i + 1)/2
Donc par exemple:
from math import floor, sqrt
def coor_to_idx(n, i, j):
return i*(2*n-i+1)//2+j-i
def idx_to_coor(n, k):
i = floor((-sqrt((2*n+1)*(2*n+1)-8*k)+2*n+1)/2)
j = k + i - i*(2*n-i+1)//2
return i, j
Par exemple:
>>> [idx_to_coor(4, i) for i in range(10)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
>>> [coor_to_idx(4, i, j) for i in range(4) for j in range(i, 4)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Etant donné que les nombres ne sont pas énormes (enfin si ceux-ci sont énormes, les calculs ne sont plus effectués en temps constant), nous pouvons donc calculer la coordonnée k - de dans O(1) , par exemple:
>>> idx_to_coor(1234567, 123456789)
(100, 5139)
ce qui équivaut à l'obtenir par énumération:
>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)
Dans ce cas, la conversion d'index en une coordonnée peut également comporter, pour les grands nombres, des erreurs d'arrondi dues à une imprécision en virgule flottante.
IIUC, vous pouvez obtenir les index en utilisant itertools
combinaisons avec remplacement
>>> ind = Tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
Pour récupérer l'index, utilisez simplement index
method
>>> ind.index((1,2))
4
Vous pouvez utiliser np.triu_indices et un dictionary :
import numpy as np
iu1 = np.triu_indices(3)
table = {(i, j): c for c, (i, j) in enumerate(Zip(*iu1))}
print(table[(1, 2)])
Sortie
4
Construire des indices supérieurs serait coûteux. Nous pouvons directement obtenir l'index correspondant comme ceci -
def triu_index(N, x, y):
# Get index corresponding to (x,y) in upper triangular list
idx = np.r_[0,np.arange(N,1,-1).cumsum()]
return idx[x]+y-x
Exemple de cycle -
In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4
Semblable à @DanielMesejo, vous pouvez utiliser np.triu_indices
avec argwhere
ou nonzero
:
my_index = (1,2)
>>> np.nonzero((np.stack(np.triu_indices(3), axis=1) == my_index).all(1))
(array([4]),)
>>> np.argwhere((np.stack(np.triu_indices(3), axis=1) == my_index).all(1))
array([[4]])
Explication:
np.stack(np.triu_indices(3), axis=1)
vous donne les indices de votre triangle supérieur dans l'ordre:
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
Donc, tout ce que vous avez à faire est de trouver où il correspond [1,2]
(ce que vous pouvez faire avec l'opérateur ==
et all
)