Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linear indexing in symmetric matrices

We can access matrices using linear indexing, which follows this pattern

0 1 2

3 4 5

6 7 8

It's easy to get the i,j coordinates for this case (n is the matrix dimension). For 0-index based, it would be.

i = index / n

j = index % n

Now, what if my matrix is symmetric and I only want to access the upper part

0 1 2 3

.. 4 5 6

..... 7 8

........ 9

I know the linear index will be given by

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

but I want to know i,j given idx. Do you guys know of any way of doing this?. I looked up this here, but I couldn't find an answer. Thanks in advance.

like image 602
balborian Avatar asked Oct 02 '13 18:10

balborian


People also ask

What is linear indexing?

A linear index is an index file organized as a sequence of key-value pairs where the keys are in sorted order and the pointers either (1) point to the position of the complete record on disk, (2) point to the position of the primary key in the primary index, or (3) are actually the value of the primary key.

How does linear indexing work in Matlab?

Linear IndexingThe expression A(14) simply extracts the 14th element of the implicit column vector. Indexing into a matrix with a single subscript in this way is often called linear indexing. The linear index of each element is shown in the upper left. From the diagram you can see that A(14) is the same as A(2,4) .

How do you store a symmetric matrix efficiently?

A symmetric matrix can be stored in about half the space, n 2 + n 2 elements. Only the upper (or lower) triangular portion of A has to be explicitly stored. The implicit portions of A can be retrieved using Equation 73. An efficient data structure for storing dense, symmetric matrices is a simple linear array.

What is the rule for symmetric matrix?

A matrix is symmetric if and only if it is equal to its transpose. All entries above the main diagonal of a symmetric matrix are reflected into equal entries below the diagonal.


3 Answers

If you want to use the indexing that you used, and you want to avoid the loop you can invert the function for the indexing. I will use k to denote the linear index, and all indices are zero based. As you have noted

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

Seeing as we are working with positive integers here, and the fact that all combinations (i,j) map onto a distinct k means that the function is invertible. The way in which I would do this is to note first of all that

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

such that if you can find the row which you are on, the column is defined by the above equation. Now consider you want the row, which is defined as

row = min{ i | k - ni + i(i-1)/2 >= 0 }.

If you solve the quadratic equation k - ni + i(i-1)/2 = 0 and take the floor of the i, this gives you the row, i.e.

row = floor( (2n+1 - sqrt( (2n+1)^2 - 8k ) ) / 2 )

then

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

In pseudocode this would be

//Given linear index k, and n the size of nxn matrix
i = floor( ( 2*n+1 - sqrt( (2n+1)*(2n+1) - 8*k ) ) / 2 ) ;
j = k - n*i + i*(i-1)/2 ;

This removes the need for the loop, and will be a lot quicker for large matrices

like image 198
Keeran Brabazon Avatar answered Oct 30 '22 03:10

Keeran Brabazon


Since nobody has posted a Matlab solution yet, here's a simple one-liner:

idxs = find(triu(true(size(A))))

Given matrix A, this will return a vector of all your indices, such that idxs(k) returns the k-th linear index into the upper triangular portion of the matrix.

like image 31
mbauman Avatar answered Oct 30 '22 01:10

mbauman


This is comment to Keeran Brabazon answer. k = j + ni - i(i-1) /2 - this is equation from your post and it's wrong, the correct equation is k = j + (2*n -1 -i)*i/2. But we can't use it for finding i.

Equation from your post could be used to find i(row index), but we can't substitue i into your equation and get j, therefore formula for j in your post is wrong, so the final result will be looks like this:

i = floor( ( 2*n+1 - sqrt( (2n+1)*(2n+1) - 8*k ) ) / 2 ) ;(exactly like yours)

j = k - (2*n-1- i)*i/2; (different from your version, and i'm getting it by substituting i into my equation)

like image 2
Михаил Ф. Avatar answered Oct 30 '22 01:10

Михаил Ф.