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
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.
EDIT
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.
FURTHER PICTURE
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.
FINALLY
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
around.
source to share
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] INTEGER, ALLOCATABLE :: XX(:) XX = PACK(X,X/=0)
will select nonzero elements from X and store in XX (on return XX = [1,2,3]).
source to share
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
ENDIF
ENDDO
ENDDO
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!).
source to share