简体   繁体   中英

Selecting a subset of an array given logical vector in Fortran

In Fortran, is it possible to select certain parts of the an array by using some vector of logical values instead of the indices? For example like this:

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 an easy (fast) way to find the indices where iszero=0?

edit: I changed the example to present a more realistic case, in previous case I just changed some values to 100.0d0, where the elementwise handling would have been ok..

edit2: had one type on the fourth row of the code

where (mymatrix==0) mymatrix = 100.0d0

will set all elements in mymatrix which are 0 to 100. If you are actually trying to do something a little more sophisticated than that, perhaps setting a matrix to have a 'checkerboard' of 1s and 0s you could try something like;

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

where m,n are the numbers of rows and columns in mymatrix. I haven't tested this latter snippet, it's just a suggestion to consider array subscript triplets sometimes.

EDIT

If you actually want to use one matrix (or vector) as the mask in the where statement and another in the assignment part, ie something like this:

where(index_matrix==0) mymatrix = 100d0

then you have (I think) to ensure that index_matrix has the same size as mymatrix . In your case you might end up with a statement such as:

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

again I haven't tested this and I don't expect that I've got the padded reshape quite right but you can probably figure out the details.

FURTHER EDIT

I'm now finding it difficult to follow the question. The statement

sum0 = sum(iszero==0)

will assign the value 1 to sum, so the statement

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

will, at run time, be something like this:

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

and I'm not sure that the rhs and lhs conform properly for Fortran. Does this compile ? If it does, does it execute correctly (with array-bounds checking) ?

Are you trying to create submatrix which holds only the 0 elements of mymatrix ? If so then I think you are going to have a hard time of it, for the general case. Unless you can define the locations of the elements you want to select in terms of either indices or a vector of subscripts or a subscript triplet, then I don't see that you can make an array on the lhs from the array on the rhs.

If the locations of the 0s are arbitrary then you might be able to do what you want by flattening the original array to rank-1 and creating a rank-1 subarray of that, but you would lose the correspondence between 2D locations and their 1D counterparts.

FINALLY

Don't forget that you can, in Fortran 2003, use a pointer to refer to a sub-matrix defined by vector or triplet subscripts, for example

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

and then pass pointer_to_array around.

For rank-1 array, the array subset can be taken by a local array mask using the intrinsic function PACK . For example (in Fortran 2003)

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

will pick out the non-zero elements from X, and store into XX (on return XX = [1,2,3]).

I think the answer is no, you cannot do what you are suggesting; at least upto FORTRAN 90 anyway. Having said that, I am 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 rapid! Even if you had a large number of these DO loops it would still be relatively fast (faster than doing it than any other language at least!).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM