2

I am trying to select sparse matrix elements row-wise based on BFS output array. Suppose my BFS output is

[1, 2, 3, 6, 4, 7, 5, 8, 11, 9, 12, 10, 13, 15, 14, 16, 17, 18, 19, 20]

and I have a sparse matrix of 20x20 for example.

Now I want to use BFS output as row index and select nonzero values from the sparse matrix in same order as that of BFS output array and plot. Here is my code through which I can do some job but not perfectly what I wanted.

a = numpy.loadtxt('sparsematrix.txt', float, delimiter=',') # import data
y = numpy.reshape(a, np.size(a))
pos = np.delete(y, np.arange(0, y.size, 19))

plt.plot(pos)
plt.xlabel(sample)
plt.ylabel(position)

Problem with the above code is:

  1. It selects every value in row-wise, but not in defined order of my BFS output. (it should use BFS output array as row index number to select nonzero values one-by-one)
  2. It selects all the values, even zeros. - How to get only nonzero values?
  3. Indexing is starting from 0 and goes to 19. I want indexing to start from 1 onwards.
Napster
  • 99
  • 8
  • 1
    It isn't immediately clear what you want. Am I correct in assuming you want to: 1) Select rows from a matrix, in the order specified by the indexes in your bfs-output array. 2) Select the non-zero elements in the selected rows starting from the first column in each row (does the order matter?) 3) present a list of the non-zero elements? example: bfs_output=[1,2,0]; matrix=[[0 3 1] [0 2 0] [4 0 0]]; list=[2 4 3 1]. Also what indexes do you want to start from 1 rather than 0 and why? – Christian Eriksson Dec 28 '17 at 12:37
  • Yes, you are assuming absolutely correct. Order matter to me because I am doing modeling and here the order is decided by bfs_output & it should select the row nonzero values one by one like Row|Col: 11, 12, 13...and so on for 1st row... and then for 2nd row it should go like 21, 22, 23...and so on...!! It keeps on selecting until bfs_output reaches to end. As I am modeling biological model, a system should have atleast 1 molecule and not 0 at initial level, so it will be easy for me to match with the molecules number. I have a small question regarding this can I ask? – Napster Dec 29 '17 at 11:12
  • Great, then my answer below suited your purposes. Sure ask your question, I'll answer if I can and if it's small enough to fit the comments :) – Christian Eriksson Dec 29 '17 at 12:42
  • @ChristianEriksson Can I consider this final output as a Matrix or it is purely an array? I want to pass the final output to another function "zgexpv" for matrix exponential calculation and plot the graph between probability (Y) and time (X). See this https://github.com/weinbe58/expokitpy/blob/master/test.py I want to use in this way and use my output as A matrix for this function. – Napster Dec 30 '17 at 08:21
  • It would be difficult to use the output as a matrix, I think. The reason why it comes out as a list/array, rather than a matrix, is that if we kept the rows and only removed the elements equal to zero, the remaining elements would (most probably) not make rows of the same length. Then the question would be how should we pad the rows to be of equal length, as in a matrix? Possibly with zeroes but that would basically make us go in a circle :) – Christian Eriksson Dec 30 '17 at 23:17
  • I'm not sure how the "zgexpv" function works or what input it expects. if it expects a matrix, or you need to perform some matrix operations before sending the input to zgexpv, I think you should try to use the original matrix. There might be a better way of representing the matrix if it's really big, but that is probably the basis for a new question. – Christian Eriksson Dec 30 '17 at 23:17
  • Okay I got you. Then I have to change something in my previous steps so that I can use sparse matrix directly as a input to zgexpv. The function take as zgexpv(m,1.0,v,0.0,anorm,wsp,iwsp,A.dot,0).... where A should be my sparse matrix. I have question now....when any sparse matrix passed to any function, then one by one values from the sparse matrix is passed to the function for calculation? Is the way it works right? If yes, then instead of selecting rows based on bfs_output can I pass the values in that fashion to this function.. it will be a matrix but order will change? Is that possible? – Napster Jan 04 '18 at 04:43

2 Answers2

2

Important Update

Now I get what you completly wanted by reading Christian's answer. I made another function to complement the one already given. See the whole program here:

sparseMatrix = ([0,4,5,0],[2,0,4,0],[0,3,3,0],[6,6,0,0])
iList = [3,1,2,4]

def AnalyzeSparseMatrix( sMatrix, iList ):
    orderedArray = [] #The array you want as output
    for i in iList:
        orderedArray += AnalyzeRowWise(sMatrix[i-1])  #Add non-zero selected line from sparse matrix
    return orderedArray #Returns a non-zero list ordered in the selected way by the BFS output list

def AnalyzeRowWise( oldArray ):
    newMatrix = []
    #Code to analize row wise
    for data in oldArray:
        if(data != 0): #Condition
            newMatrix.append(data)
    return newMatrix

#Test program
print (AnalyzeSparseMatrix(sparseMatrix, iList)) #Output: [3,3,4,5,2,4,6,6]

The new method AnalyzeSparseMatrix() takes two arguments, the first argument is the sparse matrix, the second argument is the BFS output list. The method returns a list, which is the desired list. So you can assign that list to another list you want, for example:

finalOrderedList = AnalyzeSparseMatrix( sparseMatrix, iList )

Find more details about what almost every line of code does, in the code above.

ccolin
  • 304
  • 2
  • 7
  • Hi Colin, Thank you for your comment. This will not work for me, as I want to fetch the elements from matrix using the bfs output as row index. In your case, it is using bfs output and giving nonzero values from the bfs output array but not from the matrix. – Napster Dec 28 '17 at 11:58
  • 1
    Then I would probably try using an argument for the method, let's say, edit the method to be "AnalyzeRowWise( oldMatrix )", then change all the lines that use variable "bfsOutput" to be "oldMatrix", also, you could get rid of the line assigning an array to the "bfsOutput" since you are assigning it at the method's argument. Like this you could use this method with any 1D array to analyze and get rid of the 0 in said array. If this works tell me. – ccolin Dec 28 '17 at 12:24
  • Thanks Colin for your comment and test code. I tried this one and it is also a nice solution and variation for 1D and 2D array data. Also, with the option to select nonzero, greater than zero. Further, I have a question regarding this. If I want to use this output "newMatrix" as an array into some function, then array values will be passed to function one-by-one automatically? or I have to define it? – Napster Dec 29 '17 at 11:00
  • 1
    The array is created after the function is over, so if the array has 5 indexes, for example, those 5 indexes are going to be passed to your new function. In fact, you can use a line like this "new1DArray = AnalyzeRowWise( old1DArray )" and then print the value of "new1DArray", there you will see that it is the whole array you want (the original array without the zeros). In conclusion, you don't have to define the array, the array will be the output of the function. Let me update my answer so you see what I mean. – ccolin Dec 29 '17 at 11:51
  • @Napster Updated my answer, now it does what you wanted as a whole. – ccolin Dec 29 '17 at 12:59
  • Thank you Colin for your time and effort. This made me understand the code easily how it works. It is very neat, clean and easy to work with. Thumbs up for the solution. Will it take any kind of matrix? I mean Sparse, Rectangular or Square matrix? I had to test few biological models which may have matrix of size 10000 x 10000 and practically it is hard to type every value and put it here. Is there any way to automate the creation of matrix through my chemical equations? which is generally defined by the number of molecules present in the system and, the reaction rate constant. – Napster Dec 30 '17 at 04:45
  • Yes, the only thing you have to be careful is that the number of rows in the sparse matrix is the same as the number of elements in BFS output. If number of elements in BFS output is less than number of rows in sparse matrix you will analyze less data from the sparse matrix having a "newMatrix" of less rows than your sparse matrix, if the number of rows in sparse matrix is less than BFS probably the programm will crash (let me test that out) since it won't have access to those rows the BFS output is indicating to analyze. – ccolin Dec 30 '17 at 15:20
  • Also, you can automate the creation of a big matrix using an equation values using 'nested loops'. – ccolin Dec 30 '17 at 15:22
  • Yes that is true. I got an error when the number of rows in sparse matrix was less than BFS output. It was my typing mistake but later I corrected and it worked fine. Suppose I have a reaction A + B -> C, with reaction rate constant k=4..!! Initial quantity of A is 5, B is 4 at t=0 seconds...! How can the nested loop for this? I tried to understand this post https://stackoverflow.com/questions/24591917/nested-loop-python but it doesn't have any output as sparse matrix form. You can paste any example link here and i will follow that to understand. Thanks in advance :). – Napster Jan 04 '18 at 05:02
  • See this for example: https://stackoverflow.com/questions/2397141/how-to-initialize-a-two-dimensional-array-in-python – ccolin Jan 04 '18 at 13:38
2

I've assumed that this is what you want:

bfs_output = list of row indexes where 1 is the first/top row of a matrix.
matrix m = some matrix with elements that can be 0 or non-zero
list l = a list composed of non-zero elements chosen from m

Elements from m are chosen as follows:

  1. Select the row, r, in m indicated by the first/next value in bfs_output

  2. Starting from the first column in r select the non-zero elements in r

  3. Append the elements chosen in 2 to l

  4. Repeat until no more row indexes in bfs_output

For example:

                                  0 3 1
bfs_output = [2 3 1]  &  matrix = 0 2 0    ==> list = [2 4 3 1]
                                  4 0 0

I am not sure if this is what you are after. But if it is, we can use numpy's build in selection functions to select non-zero elements from a numpy array and also to chose rows in the order we want.

from io import StringIO
import numpy as np

bfs_output = [2,3,1]
file = StringIO(u"0,3,1\n0,2,0\n4,0,0")

matrix = np.loadtxt(file, delimiter=",")

# we are subtracting 1 from all elements in bfs_output
# in order to comply with indexes starting from 1
select_rows = matrix[np.subtract(bfs_output,1)]
select_rows_1d = np.reshape(select_rows,np.size(select_rows))
list = select_rows_1d[select_rows_1d != 0]

print(list) # output = [2 4 3 1]
Christian Eriksson
  • 2,038
  • 2
  • 22
  • 28
  • Hi Christain, Thank you very much for your comment and code. Yes, this is exactly what I wanted. – Napster Dec 29 '17 at 10:42