Delete a specific row and Colum in matrix

I have a matrix of size nn and I have a list containing specific nodes in the graph in each iteration I have to remove the specific row and corresponding column based on the value in the list, how do I can know the specific row and column since the size of the matrix decreasing.
for example, I have the following 4
4 matrix

L=[8 -1 -1 0; -1 6 -1 0; -1 -1 5 0; 0 0 0 7]

if the list is the following
a=[2,3]
so I have to delete the second row and column the matrix will be
L=[8 -1 0; -1 5 0; 0 0 7]
now I have to delete the third row and column in the original matrix which is the second one now, I want a general way to use it even with huge matrices and I have to do it one by one because I know it’s possible do it all by once, I am using the following function for deleting

L = L[1:end .!= a[i], 1:end .!= a[i]]

You can use

L[setdiff(axes(L, 1), a), setdiff(axes(L, 2), a)]

or

 L[.!in.(axes(L, 1), (a,)), .!in.(axes(L, 2), (a,))]

You should benchmark to check which is faster for your arrays.

2 Likes

It would be cool, btw, if this worked:

 L[.!in.(:, (a,)), .!in.(:, (a,))]

which it seems like it should, since this does work:

 L[.!in.(begin:end, (a,)), .!in.(begin:end, (a,))]

Do you really need to delete them? Deleting a row or a column of a matrix can be very slow. One way to avoid really deleting it could be:

A = rand(10,10)
i,j = trues(10), trues(10)
i[3] = false; j[4] = false #to remove 3rd row and 4th column
B = @view A[i,j] # B is an AstractMatrix
i[7] = false
C = @view A[i,j] # C has also row 7 deleted etc

If you really need to delete them, you could do A = A[i,j]

1 Like

This would return a non-contiguous view, which is possible, but could have very negative performance consequences when you want to use the view. Contiguous or regularly spaced views are better than irregular ones like this.

of course, it may depend on what is the use of the modified matrix if a view or a copy is preferable

Thank you so much, but what you mentioned is the way of deleting the rows all at once, my problem is actually after deleting one row and column the indices of the rows and columns in the new matrix and all I need is a way to get the right indecies after each delete

Honestly, it sounds like a matrix may be a poor choice of data structure for the types of operations you want to perform. If you give a little more information about the algorithm you are trying to implement, we might be able to suggest a better data structure.

I have the following code where I am trying to calculate the smallest eigenvalue of the laplacian matrix, for that, I sort the nodes of the graph based on their degrees and start deleting the corresponding row and column for each node and check the value after each delete, the problem that when I start deleting the indices changed as I explained before so I need a way to get the right index after each delete, here is the code

using Laplacians
using LinearAlgebra
using Graphs

function eg()
	G=loadgraph("mexican.graphml", "G" , GraphIO.GraphML.GraphMLFormat())
	###########################################
	L=Matrix(laplacian_matrix(G))
    eigen_values=eigvals(L)
    min_deg = sortperm(degree(G))
    L = L[1:end .!= min_deg[1], 1:end .!= min_deg[1]]
    eigen_values=eigvals(L)
    min_eign = eigen_values[1]
    first_eigen=0
    counter=1
    for i in 2:nv(G)
         if min_eign >= first_eigen && size(L)[1] > 3
             first_eigen = eigen_values[1]
			 if min_deg[i] > size(L)[1]
             	 L = L[1:end .!= size(L)[1], 1:end .!= size(L)[1]]
			 else
				 L = L[1:end .!= min_deg[i], 1:end .!= min_deg[i]]
			 end
			 counter+=1

            eigen_values=eigvals(L)
            min_eign=eigen_values[1]
         else
             break
         end
     end
	 println("min_eign=",min_eign)
	 println("counter=",counter)
end
eg()

of course you can use any graph you have

Without making any consideration on the suitability of the thought structure, I propose an idea to obtain the indices as desired by the OP.
The implementation changes if, by any chance, the indexes to be used are sorted, for example, in ascending order.

a=[11,5,2,3,7,1]

function relindex(a)
ad=similar(a)
for i in eachindex(a)
    ad[i]=a[i]-count(<(a[i]),a[begin:i])
end
ad
end

relindex(a)


function sortrelindex(a)
    ad=similar(a)
    for i in eachindex(a)
        ad[i]=a[i]-i+1
    end
    ad
end

sortrelindex(sort(a))

Hi
thank you so much, but unfortunately I don’t have the option of sorting the indices because it represents something as it is other than that the solution you proposed is totally fine by I need it without changing anything on the list of indices :frowning:

the first function tries to do exactly that. Whatever the list of indexes.
Try it and see if it’s right for you.

If you look at the code I proposed, you incrementally modify the vector i using always the indices of the original matrix

I’ve tried to add another data structure to keep track of new indices:

# NEW functions dyn_ind
delrenum!(md, n) = ( md[n] = 0 ; for i in n+1:length(md) md[i] = ifelse(md[i]==0, 0, md[i]-1) ; end; md)
lastnode(md) = findlast(!=(0),md)

function eg()
	G=loadgraph("mexican.graphml", "G" , GraphIO.GraphML.GraphMLFormat())
	###########################################
	L=Matrix(laplacian_matrix(G))
    eigen_values=eigvals(L)
    min_deg = sortperm(degree(G))
    dyn_ind = collect(1:size(L,1))   # NEW 
    L = L[1:end .!= min_deg[1], 1:end .!= min_deg[1]]
    delrenum!(dyn_ind, min_deg[1])   # NEW
    eigen_values=eigvals(L)
    min_eign = eigen_values[1]
    first_eigen=0
    counter=1
    for i in 2:nv(G)
         if min_eign >= first_eigen && size(L,1) > 3
             first_eigen = eigen_values[1]
			 if dyn_ind[min_deg[i]] == 0
             	 L = L[1:end .!= size(L,1), 1:end .!= size(L,1)]
                 delrenum!(dyn_ind, lastnode(dyn_ind))   # NEW
			 else
			     L = L[1:end .!= dyn_ind[min_deg[i]], 1:end .!= dyn_ind[min_deg[i]]]
                 delrenum!(dyn_ind, min_deg[i])   # NEW
			 end
			 counter+=1

            eigen_values=eigvals(L)
            min_eign=eigen_values[1]
         else
             break
         end
     end
	 println("min_eign=",min_eign)
	 println("counter=",counter)
end

I think there might still be a problem, when the min_deg row to delete has already been deleted by the last row of L deletion step. But perhaps I haven’t dug enough into the workings of the algorithm.

Hope this helps.