Numpy: Efficient way to convert indices of a square matrix to its upper triangular indices
up vote
8
down vote
favorite
Question: given a tuple of index, return its order in upper triangular indices. Here is an example:
Suppose we have a square matrix A of shape (3, 3).
A has 6 upper triangular indices, namely, (0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2).
Now I know an element at index (1, 2), which is a index belongs to the upper triangular part of A. I would like to return 4 (which means it is the 5th element in all upper triangular indices.)
Any ideas on how to do that in general?
Best,
Zhihao
python numpy matrix
add a comment |
up vote
8
down vote
favorite
Question: given a tuple of index, return its order in upper triangular indices. Here is an example:
Suppose we have a square matrix A of shape (3, 3).
A has 6 upper triangular indices, namely, (0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2).
Now I know an element at index (1, 2), which is a index belongs to the upper triangular part of A. I would like to return 4 (which means it is the 5th element in all upper triangular indices.)
Any ideas on how to do that in general?
Best,
Zhihao
python numpy matrix
More general, if I have a list of indices, do we have a function to convert them to triu indices together [return a list/array of converted results]?
– Zhihao Cui
Nov 9 at 21:56
add a comment |
up vote
8
down vote
favorite
up vote
8
down vote
favorite
Question: given a tuple of index, return its order in upper triangular indices. Here is an example:
Suppose we have a square matrix A of shape (3, 3).
A has 6 upper triangular indices, namely, (0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2).
Now I know an element at index (1, 2), which is a index belongs to the upper triangular part of A. I would like to return 4 (which means it is the 5th element in all upper triangular indices.)
Any ideas on how to do that in general?
Best,
Zhihao
python numpy matrix
Question: given a tuple of index, return its order in upper triangular indices. Here is an example:
Suppose we have a square matrix A of shape (3, 3).
A has 6 upper triangular indices, namely, (0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2).
Now I know an element at index (1, 2), which is a index belongs to the upper triangular part of A. I would like to return 4 (which means it is the 5th element in all upper triangular indices.)
Any ideas on how to do that in general?
Best,
Zhihao
python numpy matrix
python numpy matrix
edited Nov 9 at 21:54
RafaelC
25.4k82648
25.4k82648
asked Nov 9 at 21:52
Zhihao Cui
654
654
More general, if I have a list of indices, do we have a function to convert them to triu indices together [return a list/array of converted results]?
– Zhihao Cui
Nov 9 at 21:56
add a comment |
More general, if I have a list of indices, do we have a function to convert them to triu indices together [return a list/array of converted results]?
– Zhihao Cui
Nov 9 at 21:56
More general, if I have a list of indices, do we have a function to convert them to triu indices together [return a list/array of converted results]?
– Zhihao Cui
Nov 9 at 21:56
More general, if I have a list of indices, do we have a function to convert them to triu indices together [return a list/array of converted results]?
– Zhihao Cui
Nov 9 at 21:56
add a comment |
6 Answers
6
active
oldest
votes
up vote
5
down vote
accepted
One can write down the explicit formula:
def utr_idx(N, i, j):
return (2*N+1-i)*i//2 + j-i
Demo:
>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
add a comment |
up vote
4
down vote
For an n×n matrix, the (i, j)-th item of the upper triangle is the i×(2×n-i+1)/2+j-i-th element of the matrix.
We can also do the math in reverse and obtain the (i, j) element for the k-th element with:
i = ⌊(-√((2n+1)2-8k)+2n+1)/2⌋ and j = k+i-i×(2×n-i+1)/2
So for example:
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
For example:
>>> [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]
Given the numbers are not huge (well if these are huge, calculations are no longer done in constant time), we can thus calculate the k-th coordinate in O(1), for example:
>>> idx_to_coor(1234567, 123456789)
(100, 5139)
which is equivalent to obtaining it through enumeration:
>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)
Here converting indices to a coordinate can also have, for large numbers, some rounding errors due to floating point imprecision.
add a comment |
up vote
2
down vote
IIUC, you can get the indexes using itertools
combinations with replacement
>>> ind = tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
To retrieve the index, just use index
method
>>> ind.index((1,2))
4
add a comment |
up vote
2
down vote
You could use np.triu_indices and a 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)])
Output
4
add a comment |
up vote
1
down vote
Similar to @DanielMesejo, you can use np.triu_indices
with either argwhere
or 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]])
Explanation:
np.stack(np.triu_indices(3), axis=1)
gives you the indices of your upper triangle in order:
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
So all you have to do is find where it matches [1,2]
(which you can do with the ==
operator and all
)
add a comment |
up vote
1
down vote
Constructing upper indices would be costly. We can directly get the corresponding index like so -
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
Sample run -
In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4
add a comment |
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
accepted
One can write down the explicit formula:
def utr_idx(N, i, j):
return (2*N+1-i)*i//2 + j-i
Demo:
>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
add a comment |
up vote
5
down vote
accepted
One can write down the explicit formula:
def utr_idx(N, i, j):
return (2*N+1-i)*i//2 + j-i
Demo:
>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
add a comment |
up vote
5
down vote
accepted
up vote
5
down vote
accepted
One can write down the explicit formula:
def utr_idx(N, i, j):
return (2*N+1-i)*i//2 + j-i
Demo:
>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123
One can write down the explicit formula:
def utr_idx(N, i, j):
return (2*N+1-i)*i//2 + j-i
Demo:
>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123
answered Nov 9 at 22:16
Paul Panzer
28.9k21240
28.9k21240
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
add a comment |
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
I just realized it lol
– Zhihao Cui
Nov 9 at 22:19
add a comment |
up vote
4
down vote
For an n×n matrix, the (i, j)-th item of the upper triangle is the i×(2×n-i+1)/2+j-i-th element of the matrix.
We can also do the math in reverse and obtain the (i, j) element for the k-th element with:
i = ⌊(-√((2n+1)2-8k)+2n+1)/2⌋ and j = k+i-i×(2×n-i+1)/2
So for example:
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
For example:
>>> [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]
Given the numbers are not huge (well if these are huge, calculations are no longer done in constant time), we can thus calculate the k-th coordinate in O(1), for example:
>>> idx_to_coor(1234567, 123456789)
(100, 5139)
which is equivalent to obtaining it through enumeration:
>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)
Here converting indices to a coordinate can also have, for large numbers, some rounding errors due to floating point imprecision.
add a comment |
up vote
4
down vote
For an n×n matrix, the (i, j)-th item of the upper triangle is the i×(2×n-i+1)/2+j-i-th element of the matrix.
We can also do the math in reverse and obtain the (i, j) element for the k-th element with:
i = ⌊(-√((2n+1)2-8k)+2n+1)/2⌋ and j = k+i-i×(2×n-i+1)/2
So for example:
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
For example:
>>> [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]
Given the numbers are not huge (well if these are huge, calculations are no longer done in constant time), we can thus calculate the k-th coordinate in O(1), for example:
>>> idx_to_coor(1234567, 123456789)
(100, 5139)
which is equivalent to obtaining it through enumeration:
>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)
Here converting indices to a coordinate can also have, for large numbers, some rounding errors due to floating point imprecision.
add a comment |
up vote
4
down vote
up vote
4
down vote
For an n×n matrix, the (i, j)-th item of the upper triangle is the i×(2×n-i+1)/2+j-i-th element of the matrix.
We can also do the math in reverse and obtain the (i, j) element for the k-th element with:
i = ⌊(-√((2n+1)2-8k)+2n+1)/2⌋ and j = k+i-i×(2×n-i+1)/2
So for example:
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
For example:
>>> [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]
Given the numbers are not huge (well if these are huge, calculations are no longer done in constant time), we can thus calculate the k-th coordinate in O(1), for example:
>>> idx_to_coor(1234567, 123456789)
(100, 5139)
which is equivalent to obtaining it through enumeration:
>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)
Here converting indices to a coordinate can also have, for large numbers, some rounding errors due to floating point imprecision.
For an n×n matrix, the (i, j)-th item of the upper triangle is the i×(2×n-i+1)/2+j-i-th element of the matrix.
We can also do the math in reverse and obtain the (i, j) element for the k-th element with:
i = ⌊(-√((2n+1)2-8k)+2n+1)/2⌋ and j = k+i-i×(2×n-i+1)/2
So for example:
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
For example:
>>> [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]
Given the numbers are not huge (well if these are huge, calculations are no longer done in constant time), we can thus calculate the k-th coordinate in O(1), for example:
>>> idx_to_coor(1234567, 123456789)
(100, 5139)
which is equivalent to obtaining it through enumeration:
>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)
Here converting indices to a coordinate can also have, for large numbers, some rounding errors due to floating point imprecision.
edited Nov 9 at 22:38
answered Nov 9 at 22:21
Willem Van Onsem
140k16132225
140k16132225
add a comment |
add a comment |
up vote
2
down vote
IIUC, you can get the indexes using itertools
combinations with replacement
>>> ind = tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
To retrieve the index, just use index
method
>>> ind.index((1,2))
4
add a comment |
up vote
2
down vote
IIUC, you can get the indexes using itertools
combinations with replacement
>>> ind = tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
To retrieve the index, just use index
method
>>> ind.index((1,2))
4
add a comment |
up vote
2
down vote
up vote
2
down vote
IIUC, you can get the indexes using itertools
combinations with replacement
>>> ind = tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
To retrieve the index, just use index
method
>>> ind.index((1,2))
4
IIUC, you can get the indexes using itertools
combinations with replacement
>>> ind = tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
To retrieve the index, just use index
method
>>> ind.index((1,2))
4
answered Nov 9 at 21:59
RafaelC
25.4k82648
25.4k82648
add a comment |
add a comment |
up vote
2
down vote
You could use np.triu_indices and a 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)])
Output
4
add a comment |
up vote
2
down vote
You could use np.triu_indices and a 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)])
Output
4
add a comment |
up vote
2
down vote
up vote
2
down vote
You could use np.triu_indices and a 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)])
Output
4
You could use np.triu_indices and a 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)])
Output
4
answered Nov 9 at 22:03
Daniel Mesejo
9,1731923
9,1731923
add a comment |
add a comment |
up vote
1
down vote
Similar to @DanielMesejo, you can use np.triu_indices
with either argwhere
or 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]])
Explanation:
np.stack(np.triu_indices(3), axis=1)
gives you the indices of your upper triangle in order:
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
So all you have to do is find where it matches [1,2]
(which you can do with the ==
operator and all
)
add a comment |
up vote
1
down vote
Similar to @DanielMesejo, you can use np.triu_indices
with either argwhere
or 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]])
Explanation:
np.stack(np.triu_indices(3), axis=1)
gives you the indices of your upper triangle in order:
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
So all you have to do is find where it matches [1,2]
(which you can do with the ==
operator and all
)
add a comment |
up vote
1
down vote
up vote
1
down vote
Similar to @DanielMesejo, you can use np.triu_indices
with either argwhere
or 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]])
Explanation:
np.stack(np.triu_indices(3), axis=1)
gives you the indices of your upper triangle in order:
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
So all you have to do is find where it matches [1,2]
(which you can do with the ==
operator and all
)
Similar to @DanielMesejo, you can use np.triu_indices
with either argwhere
or 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]])
Explanation:
np.stack(np.triu_indices(3), axis=1)
gives you the indices of your upper triangle in order:
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
So all you have to do is find where it matches [1,2]
(which you can do with the ==
operator and all
)
answered Nov 9 at 22:10
sacul
28.1k41639
28.1k41639
add a comment |
add a comment |
up vote
1
down vote
Constructing upper indices would be costly. We can directly get the corresponding index like so -
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
Sample run -
In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4
add a comment |
up vote
1
down vote
Constructing upper indices would be costly. We can directly get the corresponding index like so -
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
Sample run -
In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4
add a comment |
up vote
1
down vote
up vote
1
down vote
Constructing upper indices would be costly. We can directly get the corresponding index like so -
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
Sample run -
In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4
Constructing upper indices would be costly. We can directly get the corresponding index like so -
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
Sample run -
In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4
answered Nov 9 at 22:19
Divakar
153k1479168
153k1479168
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53233695%2fnumpy-efficient-way-to-convert-indices-of-a-square-matrix-to-its-upper-triangul%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
More general, if I have a list of indices, do we have a function to convert them to triu indices together [return a list/array of converted results]?
– Zhihao Cui
Nov 9 at 21:56