Оператор и конструкция forall
В конструкцииwhere управляющая маска задается в векторной форме, а в конструкцииforallмаска задается более гибко в виде индексированных переменных. Аналогично и выражения в блоке задаются по отношению к индексированным переменным. Другими словами выполняются маскированные конформные действия в пространстве некой секции. Пространства изменения индексов такой виртуальной секции задаются в заголовке forallтриплетами, аналогично заданию триплетами секций массивов. Заголовок конструкцииforallзадает триплеты по ряду измерений и маску отбора к полученной секции по смыслу аналогичную where.
АналогичноDo Whileконструкцияforallуправляет блоком операторов, но в отличие от Do Whileуправляющая маска векторная, в общем случае многомерная, а не скалярная. Действиянадкомпонентами секции выполняются параллельно и независимо.
Триплеты, указывающие законы изменения индексов в секции, и маску для секции задают
- в простом безблочном операторе
forall(индексИимярек=триплет, ..[, маска_секции])единственный_простой_конформный
- или в составном одноблочном операторе
forall (индексИмярек=триплет, .. &
индексИмярек=триплет [, скалярная_маска_секции] )
! маскированные действия, конформные секции, построенной
! по всем возможным комбинациям индексов из триплетов
end forall
Сначала рассмотрим четыре варианта решения простой задачи. На этих решениях покажем разницу в понимании do и forall.
Пример: найти diaPro – произведение ненулевых элементов главной диагонали.
1. Правильное решение с традиционными конструкциямиdo иif
real,dimension(1:10,1:10) :: A
real diaPro; integer i
diaPro =1
do i=1,10
if( A(i,i)/=0) diaPro = diaPro* A(i,i)
Enddo
2. Заменив do на forall, получим неправильное решение
real,dimension(1:10,1:10) :: A
realDiapro; integer i
Diapro =1
Forall(i=1:10, A(i,i)/=0) Diapro = Diapro* A(i,i)
Допущена ошибка в левой части оператора Diapro = diapro* A(i,i)–этоприсваивание,неконформное заголовку оператора Forall: diaPro–скаляр,в то время как A(i,i) определено врамках секции1:10.
3. Правильное решение с использованием оператораforall
real,dimension(1:10,1:10) :: A
real,dimension(1:10) :: Diagonal
realdiaPro; integeri
Diagonal =1;
forall (i=1:10, A(i,i)/=0)Diagonal(i)= A(i,i)
diaPro= product(Diagonal)
4. Нет решения с помощьюоператораwhere
Уforall есть аналоги:
- where- оба задают работу с многомерным объектом;
- вложенными do- обе конструкции задают закон изменения индексов в виде арифметической прогрессии по триплету в заголовках;
- do-и в теле оператора forall элементы массивов адресуются по индексам, заданным в заголовке forall.
Однако смысл адресации элементов массива в doи в forall абсолютно разный:
- в doэлементы массива выбираются последовательно по мере изменения индексов;
- в forall элементы массива выбираются независимо-параллельно, по предварительно построенным всем возможным комбинациям индексов, порядок обработки в языке не фиксирован:
Таким образом do- основа последовательного выполнения повторяющихся действий; forall - основа параллельного выполнения повторяющихся действий.
Любое присваивание массивов и where можно переписать как forall, но некоторые forall не могут быть записаны только на уровне манипуляций с массивами в where:
- например, через forall легко записать: where (A /= 0.0) B=1.0/A - сами напишите;
- однако, следующий пример forall нельзя записать на уровне манипуляций с массивами
forall (i=1:n, j=1:n) H(i,j) = 1.0/(i+j-1)
- этот оператор устанавливает элемент массива H(i, j) равным значению 1.0/ (i + j - 1) для любых пар значений i и j между 1 и n.
Forall задает:
- список имен индексов, варьируемых в секции;
- каждому поименованному индексу сопоставлен триплет, определяющий закон его изменения;
- после списка задается необязательная маска, конформная секции, которая записывается в терминах варьируемых индексов;
- над какими компонентами массивов, какие именно действия и в какой последовательности - задается в блоке оператора forall;
- порядок обработки компонент в языке не фиксирован.
Порядок действий, соответствующих forall:
- по заданным триплетам создаются списки всех возможных значений индексов;
- далее формируются все комбинации индексов;
- по комбинациям индексов формируется секция и конформная ей маска;
- затем независимо и параллельно выполняются конформные действия в последовательности заданной в блоке;
- действия выполняются только для истинных значений конформной им маски.
Получается, что это не цикл, а перечисление потенциально параллельных процессов. Синтаксис записи триплетов в forall через двоеточие ещё раз подчёркивает:
- уместность аналогии с секциями, а не циклами;
- параллельность, а не последовательность;
- чтобы потенциально параллельная конструкция стала реально таковой, необходимы два условия:
1. распараллеливающий компилятор, как IFC;
2. наличие многих процессоров.