Выбор подмножества массива по заданному логическому вектору в Фортране - PullRequest
3 голосов
/ 20 марта 2012

Можно ли в Фортране выбирать определенные части массива, используя какой-либо вектор логических значений вместо индексов? Например, как это:

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?

edit: я изменил пример, чтобы представить более реалистичный случай, в предыдущем случае я просто изменил некоторые значения на 100.0d0, где поэлементная обработка была бы в порядке ..

edit2: имел один тип в четвертой строке кода

Ответы [ 3 ]

8 голосов
/ 20 марта 2012
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_matrix имеет тот же размер, что и mymatrix,В вашем случае вы могли бы получить такое утверждение, как:

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

, опять же, я не проверял это и не ожидаю, что у меня есть правильное изменение формы, но вы, вероятно, можете понятьподробности.

ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ

Теперь мне трудно следить за вопросом.Оператор

sum0 = sum(iszero==0)

присвоит сумме значение 1, поэтому оператор

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?Если так, то я думаю, что вам будет тяжело, в общем случае.Если вы не можете определить расположение элементов, которые вы хотите выбрать, в виде индексов или вектора индексов или триплета индекса, то я не вижу, что вы можете создать массив на lhs из массива на rhs.

Если расположение нулей произвольно, то вы можете сделать то, что хотите, сгладив исходный массив до ранга 1 и создав его подрешетку ранга 1, но вы потеряете соответствие между2D-локации и их 1D-аналоги.

FINALLY

Не забывайте, что в Fortran 2003 вы можете использовать указатель для ссылки на подматрицу, определяемую каквекторные или триплетные индексы, например

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

, а затем передать pointer_to_array вокруг.

6 голосов
/ 12 ноября 2012

Для массива ранга 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]).

1 голос
/ 20 марта 2012

Я думаю, что ответ - нет, вы не можете делать то, что предлагаете;по крайней мере, до Фортрана 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, они все равно были бы относительно быстрыми (быстрее, чем это делалось, по крайней мере, на любом другом языке!).

...