在Fortran中选择给定逻辑向量的数组的子集

时间:2012-03-20 12:37:57

标签: arrays fortran logical-operators

在Fortran中,是否可以通过使用一些逻辑值向量而不是索引来选择数组的某些部分?例如:

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)

如果直接无法做到这一点,是否有一种简单(快速)的方法来找到iszero = 0的索引?

编辑:我更改了示例以呈现更实际的情况,在之前的情况下,我只是将一些值更改为100.0d0,其中元素处理可以正常。

edit2:在代码的第四行有一个类型

3 个答案:

答案 0 :(得分:8)

where (mymatrix==0) mymatrix = 100.0d0

将mymatrix中的所有元素设置为0到100.如果你实际上想要做一些比这更复杂的事情,也许设置一个矩阵以得到1和0的'棋盘'你可以尝试类似的东西;

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

其中m,n是mymatrix中的行数和列数。我没有测试过后一个片段,它只是建议有时考虑数组下标三元组。

修改

如果你真的想在where语句中使用一个矩阵(或向量)作为掩码,而在赋值部分使用另一个矩阵(或向量),例如:

where(index_matrix==0) mymatrix = 100d0

然后你(我认为)确保index_matrixmymatrix的大小相同。在您的情况下,您可能会得到如下声明:

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

我还没有对此进行测试,我不认为我的填充重塑非常正确,但你可以弄清楚细节。

进一步编辑

我现在发现很难回答这个问题。声明

sum0 = sum(iszero==0)

会将值1赋值给sum,所以语句

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

在运行时会是这样的:

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

我不确定rhs和lhs是否适合Fortran。这会编译吗?如果是,它是否正确执行(使用数组边界检查)?

您是否尝试创建仅包含submatrix的0个元素的mymatrix?如果是这样,那么对于一般情况,我认为你将会遇到困难。除非您可以根据索引或下标矢量或下标三元组来定义要选择的元素的位置,否则我不会看到您可以在rhs上的数组上的lhs上创建数组。

如果0的位置是任意的,那么你可以通过将原始数组展平为rank-1并创建其中的rank-1子阵列来做你想要的,但是你会丢失2D位置和他们的1D同行。

<强>最后

不要忘记,在Fortran 2003中,您可以使用指针来引用由向量或三元组下标定义的子矩阵,例如

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

然后传递pointer_to_array

答案 1 :(得分:6)

对于rank-1数组,可以使用内部函数PACK通过本地数组掩码获取数组子集。例如(在Fortran 2003中)

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

将从X中挑出非零元素,并存储到XX中(返回XX = [1,2,3])。

答案 2 :(得分:1)

我认为答案是否定的,你不能做你的建议;至少在FORTRAN 90之前。话虽如此,我不知道为什么会这样。

DO I = 1, 3
    DO J = 1, 3
        IF (iszero(I) == 0 .AND. iszero(J) == 0)
            mymatrix(I, J) = 100.0d0
        ENDIF
    ENDDO
ENDDO
对于3x3阵列来说,像这样的东西会很快!即使你有大量的这些DO循环,它仍然会相对较快(至少比任何其他语言更快!)。