Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Алгоритмы решения систем линейных уравнений с блочно-ленточными матрицами. Монография

.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 2 31
Рисунок 17. Блочная двухдиагональная верхнетреугольная матрица.
Пример 3. Рассмотрим тесное гнездо двух циклов:
for (j = 0; j < m; j++) {
for (k = 0; k < j; k++) {
LoopBody(j,k);
}}
Пространство итераций этого гнезда является треугольником, поэ­тому такой двойной цикл иногда называют «треугольным».
Конец примера.
Поскольку граница внутреннего цикла не является константной на эта-
пе компиляции, оптимизирующие компиляторы не могут делать раскрутку таких циклов непосредственно.
Сначала делаем раскрутку внешнего цикла. В результате получится код
в виде последовательности копий тела внешнего цикла, в которых вместо счетчика внешнего цикла подставлены его значения. В каждой копии тела внешнего цикла есть одномерный цикл, который ранее был внутренним циклом, но у этого цикла уже после подстановки границы становятся кон­стантными. Теперь следует сделать раскрутки каждого из этих циклов.
Таким образом, раскрутка двойного треугольного цикла сводится к рас-
круткам одномерных циклов.
При численных методах решения краевых задач в трехмерных областях
могут возникать тройные пирамидальные циклы. Раскрутку таких гнезд ци­клов можно делать аналогично, начиная с внешнего (объемлющего) цикла.
32 Б. Я. Штейнберг, О. Б. Штейнберг
Оптимизирующие компиляторы не всегда делают раскрутку цикла. Экс­перименты показали отсутствие раскрутки в GCC (вручную сделанная рас­крутка ускоряет код в 2 раза).
Подстановка и вынос вычисления подвыражений
Подстановка — это преобразование, которое похоже на одноименное преобразование в алгебре: если переменная равна какому-то выражению, то всюду вместо этой переменной можно подставлять равное ей выражение.
В программе подстановка является эквивалентным преобразованием не всегда, условия эквивалентной применимости формулируются в терминах информационных зависимостей.
Пример 4. Подстановкой можно из кода
x = a+b; ... y = x*c; z = x-d;
получить следующий:
x = a+b; ... y = (a+b)*c; z = a+b-d;
Конец примера.
(2)
(3)
Вынос вычисления подвыражений — это преобразование, обратное к подстановке. Например, это преобразование может из фрагмента кода (3) получить (2). Один из фрагментов (2) или (3) может работать быстрее, а другой — медленнее. Фрагмент (2) имеет меньше вычислительных опе­раций, а фрагмент (3) иногда может иметь меньше переменных (если в данном примере исключается переменная x, а переменные a и b уже при­сутствовали в преобразуемом фрагменте) и использовать меньше обменов между регистрами и памятью (м. б. кэш-памятью). Количество свободных регистров при выполнении фрагмента кода зависит от контекста (окруже­ния этого фрагмента кода).
Всегда дает ускорение частный случай подстановки — протягивание констант (правая часть подставляемого выражения — константа). Вынос вычисления подвыражений из цикла (вынос инвариантных вычислений) практически всегда дает ускорение.
Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 2 33
Гнездование цикла
Гнездование цикла — это преобразование с параметром p, который ино-
гда обозначает количество вычислительных устройств, участвующих в вы­числении цикла.
Гнездование цикла (в предположении, что количество итераций цикла
делится нацело на параметр p) заменяет цикл
for (j = 0; j < N; j++) {
LoopBoby(j);
}
двойным гнездом циклов
for (j1 = 0; j1 < N/p; j1++) {
for (j2 = 0; j2 < p; j2++) {
j = (N/p)*j1+j2;
LoopBoby(j);
}}
или следующим двойным гнездом циклов
for (j1 = 0; j1 < p; j1++) {
for (j2 = 0; j2 < N/p; j2++) {
j = p*j1+j2;
LoopBoby(j);
}}
Выбор, каким из двух гнезд циклов следует заменить исходный цикл,
зависит от того, где нужен цикл с p итерациями: внутренним циклом гнезда или внешним. Например, если предполагается заменить внутренний цикл гнезда командой векторизатора, обрабатывающего векторы длины p, то ну­жен внутренний цикл длины p (такое преобразование рассматривается да­лее); если предполагается выполнять цикл на p асинхронных вычислитель­ных устройствах (вычислительных ядрах процессора или узлах кластера), следует внешний цикл гнезда получить длиной p.
При использовании тайлинга параметр p может быть размером тайла
(блока).
Если количество итераций исходного цикла не делится нацело на пара-
метр гнездования, то к результирующему двойному гнезду циклов дописы­вается еще одномерный цикл, вычисляющий несколько итераций (остаток от деления числа N на число p).
34 Б. Я. Штейнберг, О. Б. Штейнберг
Тайлинг
Тайлинг — это преобразование программ, переводящее к блочным вычислениям [18; 25; 26; 27; 28; 29; 48; 50] (слово тайл (tile) означает черепица).
Идея перехода к блочным вычислениям (тайлинга) состоит в том, что­бы разбить программу на малое количество таких частей, вычисление ка­ждой из которых использует множество данных, которые помещаются в кэш-памяти.
Самый простой пример тайлинга — блочное умножение матриц. Если умножаются матрицы размера N*N и матрицы разбить на квадратные блоки m*m, то блочных строк и столбцов у этих матриц получается N/m. Параметр m выбирается таким, чтобы в кэш-памяти поместилось 3 блока: два перемножаемых и результирующий. Тогда при таком блочном алгорит­ме количество умножений (и сложений) чисел будет равно N3 (не зависит от m), а количество обращений к оперативной памяти (долгая операция) будет N3/m (количество обращений к кэш-памяти N3).
Тайлинг применяется только к тесным гнездам циклов.
Не к любому тесному гнезду циклов можно применить тайлинг.
Переход к тайлингу можно представить как суперпозицию двух пре­образований: «гнездование цикла» и «перестановка циклов» (точнее, за­головков циклов). Условие перестановки циклов сложно формулируется в терминах информационных зависимостей [60]. Такие зависимости не опи­сываются графом информационных связей. Для описания таких зависимо­стей можно воспользоваться решетчатыми графами [21; 61].
Если к гнезду циклов непосредственно можно применить тайлинг, то тайлы (фрагменты пространства итераций) получаются прямоугольника­ми (для двойного гнезда циклов) или прямоугольными параллелепипедами (для тройного гнезда циклов).
Во многих случаях для применения тайлинга приходится предвари­тельно линейно преобразовывать (скашивать) пространство итераций гнезда циклов, что преобразует информационные зависимости к виду, не мешающему тайлингу. Изменение пространства итераций происхо­дит за счет изменения гнезда циклов. Если после такого преобразования вернуться к исходному пространству итераций обратным линейным пре­образованием, то тайлы окажутся параллелепипедами (в случае трой­ного гнезда циклов) непрямоугольными (скошенными). Такой скошен­ный тайлинг (skewed tiling) применим к значительно более широкому
Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 2 35
множеству гнезд циклов, которые встречаются в практически значимых задачах [18].
Чтобы тайлинг был эффективен, желательно, чтобы количество циклов
гнезда было больше, чем наибольшая размерность массивов, входящих в это гнездо. Например, программа перемножения матриц представляет­ся тройным циклом, а входящие в него массивы (матрицы) двумерные. Другой пример — программа, вычисляющая свертку двух векторов: ци­клов в гнезде 2, а входящие в гнездо массивы одномерные (описывающие векторы).
Сочетание тайлинга и распараллеливания (параллельное выполне-
ние тайлов) дает высокое ускорение, иногда в десятки раз [18; 25; 26; 27; 28; 29].
Линеаризация выражений
Во многих случаях для ускорения программы возникает задача упро-
щения выражений. Особенно часто такая задача возникает для оптимиза­ции индексных выражений после некоторых оптимизирующих преобра­зований, таких как гнездование цикла или тайлинг. Понятие «упрощение выражения» может иметь неоднозначное толкование. Например, какое из следующих двух равных выражений
a*b + a*c + d*c = a*(b + c) + d*c
считать более простым — левое или правое?
Левое представлено однородной формулой, а правое выражение содер-
жит меньше вычислительных операций.
Индексные выражения массивов желательно представить как аффинные
выражения относительно счетчиков циклов. Это необходимо для определе­ния информационных зависимостей. В частности, линеаризация выполня­ет так называемые смешанные вычисления — операции с константами на этапе компиляции.
Пример 5. Выражение X[(j + 1) + j + 2] заменяется выражением
X[(2* j + 3].
Линеаризация может быть уместна, например, при приведении тела рекуррентного цикла к некоторому шаблонному виду.
Конец примера.
36 Б. Я. Штейнберг, О. Б. Штейнберг
Пример 6. Программный цикл
for (j = 1; j < N+1; j++) { X[j] = X[j-1] + A[j]*X[j-1] + B[j]; }
можно привести к виду
for (j = 1; j < N+1; j++) { X[j] = (A[j] + 1)*X[j-1] + B[j]; }
Конец примера.
2.2. Предкомпилятор для ускорения алгоритмов
Предкомпилятор — это конвертор, преобразующий код перед компиля­цией.
Причин для разработки предкомпилятора может быть несколько.
Одна из причин, оправдывающая затраты на разработку предкомпиля­тора, состоит в том, что современные оптимизирующие компиляторы мо­гут не очень эффективно оптимизировать.
Еще одной причиной может быть наличие параметров в программе, зна­чение которых заранее не известно. Предположим, что в программе име­ются циклы, в теле которых небольшое количество операций, а количество итераций невелико, но заранее не известно. Например, размерность блока блочно-ленточной матрицы.
Предкомпилятор должен преобразовать код к такому виду, который бы­стро выполняется после компиляции даже без оптимизации.
Для решателя СЛАУ с блочно-ленточной матрицей одним из неизвест­ных заранее параметров может быть размерность блоков, стоящих по ди­агоналям. Эта размерность может определяться, например, либо количе­ством неизвестных функций в системе дифференциальных уравнений, из которой получена СЛАУ при использовании сеточного метода, либо коли­чеством связей между элементами при методе конечных элементов.
Для одного из решателей пакета ACELAN-COMPOS сделан SourceToSource конвертор (компилятор) [62] основанный на ОРС (Оптими­зирующей распараллеливающей системы www.ops.rsu.ru), выполняющий раскрутки двойных циклов, предварительно выполняя вынос инвариант­ных вычислений.
3. О ПАРАЛЛЕЛЬНЫХ ПРЯМЫХ
АЛГОРИТМАХ РЕШЕНИЯ СЛАУ С ЛЕНТОЧНЫМИ
И БЛОЧНО-ЛЕНТОЧНЫМИ МАТРИЦАМИ
В данной главе рассматриваются параллельные алгоритмы решения
систем линейных уравнений с ленточными матрицами. К решению таких систем уравнений сводится вычисление программных циклов с линейной рекуррентной зависимостью. Для более полного ознакомления с парал­лельными численными методами решения систем линейных алгебраиче­ских уравнений можно порекомендовать обзор [7; 8], а также соответству­ющие главы из книг [5; 15; 19].
Матрица A = { aij} размера n*n называется ленточной, если существуют
такие натуральные числа b и c, значительно меньшие n, что для любых i, j таких, что i j < – b или i j > c, выполняется условие aij = 0. Если b и c — наименьшие такие числа, то число d = b + c называется шириной ленты. В памяти компьютера такая матрица представляется в виде одномерных массивов, в которых хранятся элементы ненулевых диагоналей.
Иногда от матриц будем требовать условие диагонального преоблада-
ния. Напомним, что матрица A имеет диагональное преобладание, если в любой строке модуль диагонального элемента больше суммы модулей остальных элементов строки. Для СЛАУ с трехдиагональной матрицей и преобладанием по главной диагонали предлагается метод параллельной ре­дукции [14], а обобщение диагонального преобладания на случай блочных диагоналей и условия устойчивой сходимости описаны в [15].
Следует отметить, что на компьютерах прошлых лет программные реа-
лизации рассматриваемых алгоритмов не могли быть эффективны. Критика многих старых параллельных алгоритмов линейной алгебры приводится в [21]. В обзорах [7; 8; 21] упоминаются такие алгоритмы, которые не толь­ко не учитывали время доступа к данным, но и использовали количество вычислительных устройств, пропорциональное или большее количества вычислительных операций.
38 Б. Я. Штейнберг, О. Б. Штейнберг
ha
3.1. Параллельное решение СЛАУ
с двухдиагональными и блочными
двухдиагональными матрицами
Будем рассматривать систему уравнений с ленточной двухдиагональной матрицей следующего вида
 
     
 
Ясно, что эта система имеет единственное решение тогда и только тогда, когда все элементы главной диагонали отличны от нуля. В этом случае каждое i-ое уравнение можно разделить на a можно выполнить одновременно. В результате задача сведется к реше­нию системы уравнений с матрицей следующего вида с обновленными значениями bi и hi.
00
hab
111
hab
222
.
hab
333
.......
 
hab
111
nnn
. Все эти деления
i
1
 
1
   
1
1
 
 
h
0
hb
11
hb
22
(4)
hb
33
.......
1
hb
11
nn
Рассмотрим параллельный алгоритм решения такой системы уравне­ний. На первом шаге следует одновременно получить нули на месте эле­ментов b
. Для этого из каждой i-ой строки (кроме первой) надо вычесть
i
предыдущую, умноженную на число bi. При этом все элементы подди­агонали станут нулевыми, но элементы второй поддиагонали окажутся ненулевыми.
Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 3 39
00000001
00000001
h
 
        
 
0000001
hb
0000010
hb
0000100
hb
0001000
hb
0010000
hb
0100000
hb
1000000
hb
0
11
22
33
~ ~
44
55
66
77
h
0
00000010
h
1
0000010
hb
22
0000100
hb
33
0001000
hb
44
 
0010000
hb
55
0100000
hb
66
 
1000000
hb
77
На втором шаге из каждой i-ой строки (кроме первых двух) надо вы-
честь строку с номером (i – 2), умноженную на число b
. При этом все эле-
i
менты второй поддиагонали станут нулевыми, но элементы в четвертой поддиагонали окажутся ненулевыми.
00000001
h
00000001
h
 
        
 
0
00000010
h
1
00000100
h
2
00001000
h
3
0001000
hb
44
 
0010000
hb
55
0100000
hb
66
 
1000000
hb
77
 
   
~ ~
    
 
На k-ом шаге из каждой i-ой строки (кроме первых 2
строку с номером i – 2 поддиагонали с номером 2
k – 1
, умноженную на число bi. При этом все элементы
k –1
станут нулевыми, но элементы поддиагонали
k –1
) надо вычесть
0
00000010
h
1
00000100
h
2
00001000
h
3
00010000
h
4
 
00100000
h
5
01000000
h
6
 
10000000
h
7
с номером 2k окажутся ненулевыми. Через ]log(n)[ шагов матрица системы станет единичной, и в правой части будет получен вектор-решение.
Здесь и далее логарифмы берутся по основанию 2 и операция ]a[ озна-
чает наименьшее целое, не меньшее числа a.
Заметим, что в этом алгоритме ненулевая поддиагональ после каждо-
го шага оказывается вдвое дальше от главной диагонали, чем перед этим шагом.
Для верхнетреугольных двухдиагональных матриц алгоритм решения
системы уравнений выглядит аналогичным образом.
40 Б. Я. Штейнберг, О. Б. Штейнберг
00
11
22
bh
bh
bh
       
 
11
22
33
11
.......
nn
H
BH
BH
BH
BH
−−
       
 
1
1
1
1
.
h
3
. . . . .. .
h
1
1
n
Будем рассматривать системы линейных уравнений следующего вида:
1
0
1
1
.
1
1
Здесь элементами n*n матрицы являются матрицы (блоки) размера m*m. Координатами вектора правой части системы являются векторы дли-
ны m. Параллельный алгоритм решения такой системы уравнений аналоги­чен алгоритму в скалярном случае.
3.2. О последовательном алгоритме,
соответствующем параллельному алгоритму
решения СЛАУ с двухдиагональной матрицей
Выше описан параллельный алгоритм решения СЛАУ с двухдиагональ­ной матрицей. При создании программ, основанных на этом алгоритме, могут возникать нелегко обнаруживаемые ошибки. Остановимся на этой проблеме подробнее, иллюстрируя ее на скалярном случае, хотя все рас­суждения верны и для блочной двухдиагональной матрицы.
Во многих системах параллельного программирования, например в OpenMP, распараллеливаются циклы. Поэтому интересно найти такой по­следовательный алгоритм, распараллеливание цикла в котором приведет к описанному ранее параллельному алгоритму решения СЛАУ с двухдиа­гональной матрицей. Попытаемся записать последовательную программу, соответствующую этому алгоритму.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]