Selecting a subset of an array given by a boolean vector in Fortran

In Fortran, is it possible to select specific parts of an array using a vector of vector values ​​instead of indices? For example, for example:

iszero(1) = 0
iszero(2) = 1
iszero(3) = 0
sum0 = sum(iszero) !was  sum0 = sum(iszero==0)
!mymatrix is arbitary is 3 times 3 array
mysubmatrix(1:sum0,1:sum0) = mymatrix(iszero==0,iszero==0)
call dtrmv('l','n','u',sum0,mysubmatrix(1:sum0,1:sum0),sum0,x(1:sum0)),1)


If this is not possible directly, is there a simple (fast) way to find the indices where iszero = 0?

edit: I modified the example to present a more realistic case, in the previous case I just changed some values ​​to 100.0d0 where basic handling would be fine.

edit2: had one type in the fourth line of code


source to share

3 answers

where (mymatrix==0) mymatrix = 100.0d0


will set all the elements in mymatrix to be between 0 and 100. If you are actually trying to do something more complex than this, perhaps to set a checkerboard matrix of 1 and 0, you can try something like:

mymatrix(1:m:2,2:n:2) = 100d0


where m, n are the number of rows and columns in mymatrix. I have not tested this last snippet, it is just a suggestion to consider triplets of array indices sometimes.


If you really want to use one matrix (or vector) as a mask in the where clause and another in the assignment part, then there is something like this:

where(index_matrix==0) mymatrix = 100d0


then you have (I think) to index_matrix

have the same size as mymatrix

. In your case, you can specify an operator, for example:

where(reshape([0,1],[3,3],pad=[0,1])==0) mymatrix = 100d0


again I have not tested this and I do not expect I have a fixed change, but you can perhaps figure out the details.


Now I find it difficult to understand this question. Statement

sum0 = sum(iszero==0)


will assign the value 1, so the statement

mysubmatrix(1:sum0,1:sum0) = mymatrix(iszero==0,iszero==0)


at runtime it will look something like this:

mysubmatrix(1:1,1:1) = mymatrix(iszero==0,iszero==0)


and I'm not sure if rhs and lhs are Fortran correct. Will this compile? If so, is it being executed correctly (with array bounds checking)?

Are you trying to create submatrix

one that only contains 0 items mymatrix

? If so, I think it will be difficult for you to do it in general. If you can't figure out the locations of the elements you want to select in terms of indices or a vector of indices or an index triplet, then I don't see that you can make an array on lhs from an array on rhs.

If the 0s locations are arbitrary, then you can do what you want by flattening the original array to rank-1 and creating a subarray of rank-1, but you will lose alignment between the 2D locations and their 1D counterparts.


Don't forget that in Fortran 2003 you can use a pointer to refer to a submatrix defined by vector or triplet indices, for example

pointer_to_array => target_array(1:10:2,2:10:2)


and then walk pointer_to_array




For a rank-1 array, a subset of the array can be taken with a local array mask using the built-in function PACK

. For example (in Fortran 2003)

INTEGER :: X(5) = [1,2,0,3,0]
XX = PACK(X,X/=0)


will select nonzero elements from X and store in XX (on return XX = [1,2,3]).



I think the answer is no, you cannot do what you suggest; at least up to FORTRAN 90 anyway. Having said that, I'm not sure why something like

DO I = 1, 3
    DO J = 1, 3
        IF (iszero(I) == 0 .AND. iszero(J) == 0)
            mymatrix(I, J) = 100.0d0


Something like this for a 3x3 array would be fast! Even if you had a large number of these DO loops, it would still be relatively fast (faster than doing this than any other language, at least!).



All Articles