Матрицы коэффициентов
n неизвестными x0, x1, ѕ, xn-1 может быть
определено при помощи выражения$$a_0 x_0 + a_1 x_1 + \ldots + a_{n-1} x_{n-1} = b$$
где величины a0,a1,...,an-1
и b представляют собой постоянные значения.
Множество из n
Ax = b,
где A=(ai,j) есть вещественная матрица размера nxn, а векторы b и x состоят из n элементов.
Под задачей А и вектора b обычно понимается нахождение значения
вектора неизвестных x, при котором выполняются все уравнения
системы.
Метод Гаусса – широко известный прямой алгоритм А посредством эквивалентных
преобразований (не меняющих решение системы (8.2)) к треугольному
виду, после чего значения искомых неизвестных могут быть получены
непосредственно в явном виде.
В подразделе дается общая характеристика метода Гаусса,
достаточная для начального понимания алгоритма и позволяющая
рассмотреть возможные способы параллельных вычислений при
Метод Гаусса основывается на возможности выполнения
преобразований
Метод Гаусса включает последовательное выполнение двух этапов.
На первом этапе – прямой ход метода Гаусса – исходная
Ux=c,
где матрица коэффициентов получаемой системы имеет вид$$U= \begin{pmatrix} u_{0,0} u_{0,1} \ldots u_{0, n-1} \\ 0 u_{1,1} \ldots u_{1, n-1} \\ \ldots \\ 0 0 \ldots u_{n-1,n-1} \end{pmatrix} .$$
На обратном ходе метода Гаусса (второй этап алгоритма)
осуществляется определение значений неизвестных. Из последнего
уравнения преобразованной системы может быть вычислено значение
переменной xn-1, после этого из предпоследнего уравнения
становится возможным определение переменной xn-2 и т.д.
Прямой ход метода Гаусса состоит в последовательном исключении
неизвестных в уравнениях решаемой i, 0<=i<n-1, метода производится исключение неизвестной i для всех уравнений с номерами k, большими i (т.е. i<k<=n-1 ).
Для этого из этих уравнений осуществляется вычитание строки i,
умноженной на константу ( aki/aii ), с тем чтобы результирующий
коэффициент при неизвестной xi в строках оказался нулевым – все
необходимые вычисления могут быть определены при помощи
соотношений:$$\left\phantom{(}
\begin{aligned}
a'_{kj} = a_{kj}-(a_{kj} / a_{ii})\cdot a_{ij}, \\
b'_k = b_k-(a_{kj} / a_{ii})\cdot b_i,
\end{aligned}
\right.
\quad i \le j \le n-1, \; i < k \le n-1, \; 0 \le i < n-1$$
(следует отметить, что аналогичные вычисления выполняются и над
вектором b ).
Поясним выполнение прямого хода метода Гаусса на примере
На первой итерации производится исключение неизвестной x0 из второй и третьей строки. Для этого из этих строк нужно вычесть первую строку, умноженную соответственно на 2 и 1. После этих преобразований система уравнений принимает вид:$$\begin{aligned} x_0 + 3x_1 + 2x_2=\phantom{0}1, \\ x_1 + \phantom{0}x_2 =16, \\ x_1 + 4x_2 = 25. \end{aligned}$$
В результате остается выполнить последнюю итерацию и исключить
неизвестную x1 из третьего уравнения. Для этого необходимо
вычесть вторую строку, и в окончательной форме система имеет
следующий вид:$$\begin{aligned}
x_0 + 3x_1 + 2x_2=\phantom{0}1, \\
x_1 + \phantom{0}x_2 =16, \\
3x_2 = 9.
\end{aligned}$$
На рис. 8.1 представлена общая схема состояния данных на i -й
итерации прямого хода i, уже являются нулевыми. На i -й итерации прямого хода метода
Гаусса осуществляется обнуление коэффициентов столбца i,
расположенных ниже главной диагонали, путем вычитания строки i,
умноженной на нужную ненулевую константу. После проведения (n-1)
подобной итерации матрица, определяющая
(рис 8.1) Итерация прямого хода алгоритма ГауссаПри выполнении прямого хода метода Гаусса строка, которая
используется для исключения неизвестных, носит наименование ведущей, а диагональный элемент ведущей строки называется ведущим
элементом. Как можно заметить, выполнение вычислений является
возможным только, если ведущий элемент имеет ненулевое значение.
Более того, если ведущий элемент ai,i имеет малое значение, то
деление и умножение строк на этот элемент может приводить к
накоплению вычислительной погрешности и вычислительной
неустойчивости алгоритма.
Возможный способ избежать подобной проблемы может состоять в следующем: при выполнении каждой очередной итерации прямого хода метода Гаусса следует определить коэффициент с максимальным значением по абсолютной величине в столбце, соответствующем исключаемой неизвестной, т.е.$$y=\max_{i\le k\le n-1} |a_{ki}|$$ и выбрать в качестве ведущей строку, в которой этот коэффициент располагается (данная схема выбора ведущего значения носит наименование метода главных элементов).
Вычислительная сложность прямого хода O(n3).
После приведения матрицы коэффициентов к верхнему треугольному
виду становится возможным определение значений неизвестных. Из
последнего уравнения преобразованной системы может быть вычислено
значение переменной xn-1, после этого из предпоследнего уравнения
становится возможным определение переменной xn-2 и т.д. В общем
виде выполняемые вычисления при обратном ходе метода Гаусса могут
быть представлены при помощи соотношений:$$\begin{aligned}
x_{x-1} = b_{n-1} / a_{n-1,n-1}, \\
x_i =(b_i - \sum_{j=i+1}^{n-1} a_{ij}x_j)/a_{ii}, \;
i=n-2,n-3,\ldots,0.
\end{aligned}$$
Поясним, как и ранее, выполнение обратного хода метода Гаусса
на примере рассмотренной в п. 8.2.1.1
Из последнего уравнения системы можно определить, что
неизвестная x2 имеет значение 3. В результате становится
возможным разрешение второго уравнения и определение значение
неизвестной x1=13, т.е.$$\begin{aligned}
x_0 + 3x_1 + 2x_2=\phantom{0}1, \\
x_1\;\; \phantom{+ 0x_2} =13, \\
x_2 = \phantom{0}3.
\end{aligned}$$
На последней итерации обратного хода метода Гаусса
определяется значение неизвестной x0, равное -44.
С учетом последующего параллельного выполнения можно отметить,
что вычисление получаемых значений неизвестных может выполняться
сразу во всех уравнениях системы (и эти действия могут
выполняться в уравнениях одновременно и независимо друг от
друга). Так, в рассматриваемом примере после определения значения
неизвестной x2 система уравнений может быть приведена к виду$$\begin{aligned}
x_0 + 3x_1 \phantom{+ 2x_2}=-5, \\
x_1\;\; \phantom{+ 0x_2} =13, \\
x_2 = \phantom{0}3.
\end{aligned}$$
Вычислительная сложность обратного хода O(n2).
При внимательном рассмотрении метода Гаусса можно заметить,
что все вычисления сводятся к однотипным вычислительным операциям
над строками матрицы коэффициентов A и соответствующего
элемента вектора b.
Рассмотрим общую схему параллельных вычислений и возникающие при этом информационные зависимости между базовыми подзадачами.
Для выполнения прямого хода метода Гаусса необходимо
осуществить (n-1) итерацию по исключению неизвестных для
преобразования матрицы коэффициентов A к верхнему треугольному
виду.
Выполнение итерации i, 0<=i<n-1, прямого хода метода Гаусса
включает ряд последовательных действий. Прежде всего, в самом
начале итерации необходимо выбрать ведущую строку, которая при
использовании метода главных элементов определяется поиском
строки с наибольшим по абсолютной величине значением среди
элементов столбца i, соответствующего исключаемой переменной xi.
Поскольку строки матрицы A распределены по подзадачам, для поиска
максимального значения подзадачи с номерами k, k<i, должны
обменяться своими элементами при исключаемой переменной xi. После
сбора всех необходимых данных в каждой подзадаче может быть
определено, какая из подзадач содержит ведущую строку и какое
значение является ведущим элементом.
Далее для продолжения вычислений ведущая подзадача должна
разослать свою строку матрицы A и соответствующий элемент вектора b всем остальным подзадачам с номерами k, k<i. Получив ведущую
строку, подзадачи выполняют вычитание строк, обеспечивая тем
самым исключение соответствующей неизвестной xi.
При выполнении обратного хода метода Гаусса подзадачи
выполняют необходимые вычисления для нахождения значения
неизвестных. Как только какая-либо подзадача i, 0<=i<n-1,
определяет значение своей переменной xi, это значение должно быть
разослано всем подзадачам с номерами k, k<i. Далее подзадачи
подставляют полученное значение новой неизвестной и выполняют
корректировку значений для элементов вектора b.
Выделенные базовые подзадачи характеризуются одинаковой
вычислительной трудоемкостью и сбалансированным объемом
передаваемых данных. В случае когда размер матрицы, описывающей p<n ), базовые подзадачи можно
укрупнить, объединив в рамках одной подзадачи несколько строк
матрицы. Однако применение использованной в лекциях
6 и 7
последовательной схемы разделения данных для параллельного A делится на наборы (полосы) строк вида
(см. рис. 8.2):$$A=(A_0, A_2, \ldots, A_{p-1})^T, A_i = (a_{i_0}, a_{i_1}, \ldots, a_{i_{k-1}}), \;
i_j=i+jp, \; 0 \le j < k, \; k=n/p$$
(рис 8.2) Пример использования ленточной циклической схемы разделения строк матрицы между тремя процессорамиСопоставив схему разделения данных и порядок выполнения вычислений в методе Гаусса, можно отметить, что использование циклического способа формирования полос позволяет обеспечить лучшую балансировку вычислительной нагрузки между подзадачами.
Распределение подзадач между процессорами должно учитывать
характер выполняемых в методе Гаусса коммуникационных операций.
Основным видом информационного взаимодействия подзадач является
Оценим трудоемкость рассмотренного параллельного варианта
метода Гаусса. Пусть, как и ранее, n есть порядок решаемой p, p<n, обозначает число
используемых процессоров. Тем самым, матрица коэффициентов А
имеет размер nxn, и, соответственно, n/p есть размер полосы
матрицы А на каждом процессоре.
Прежде всего, несложно показать, что общее время выполнения последовательного варианта метода Гаусса составляет:
$$T_1=2n^3/3+n^2.$$Определим теперь сложность параллельного варианта метода
Гаусса. При выполнении прямого хода алгоритма на каждой итерации
для выбора ведущей строки каждый процессор должен осуществить
выбор максимального значения в столбце с исключаемой неизвестной
в пределах своей полосы. Начальный размер полос на процессорах
равен n/p, но по мере исключения неизвестных количество строк в
полосах для обработки постепенно сокращается. Текущий размер
полос приближенно можно оценить как (n-i)/p, где i, 0<=i<n-1,
есть номер выполняемой итерации прямого хода метода Гаусса. Далее
после сбора полученных максимальных значений, определения и
рассылки ведущей строки каждый процессор должен выполнить
вычитание ведущей строки из каждой строки оставшейся части строк
своей полосы матрицы A. Количество элементов строки, подлежащих
обработке, также сокращается при исключении неизвестных, и
текущее число элементов строки для вычислений оценивается
величиной (n-i). Тем самым, сложность процедуры вычитания строк
оценивается как 2x(n-i) операций (перед вычитанием ведущая строка
умножается на масштабирующую величину aik/aii ). С учетом
выполняемого количества итераций общее число операций
параллельного варианта прямого хода метода Гаусса определяется
выражением:$$T_p^1=\sum_{i=0}^{n-2}
\left[
\frac{(n-i)}{p}+\frac{(n-i)}{p}\cdot 2(n-i)
\right]
= \frac1p \sum_{i=0}^{n-2}
\left[
(n-i)+2(n-i)^2
\right] .$$
На каждой итерации обратного хода
Просуммировав полученные выражения, можно получить$$T_p=\frac1p \sum_{i=0}^{n-2} [(n-i)+2(n-i)^2] + \frac2p \sum_{i=0}^{n-2} (n-i) = \frac1p \sum_{i=0}^{n-2} [3(n-i)+2(n-i)^2] = \frac1p \sum_{i=2}^{n} (3i+2i^2) .$$
Как результат выполненного анализа, показатели ускорения и эффективности параллельного варианта метода Гаусса могут быть определены при помощи соотношений следующего вида:$$S_p = \frac{(2n^3/3+n^2)}{\frac1p \sum\limits_{i=2}^{n}(3i+2i^2)}, \quad E_p = \frac{(2n^3/3+n^2)}{\sum\limits_{i=2}^{n}(3i+2i^2)} .$$
Полученные соотношения имеют достаточно сложный вид для
оценивания. Вместе с тем можно показать, что сложность
параллельного алгоритма имеет порядок ~(2n3/3)/p, и, тем самым,
балансировка вычислительной нагрузки между процессорами в целом
является достаточно равномерной.
Дополним сформированные показатели вычислительной сложности
метода Гаусса оценкой затрат на выполнение операций передачи
данных между процессорами. При выполнении прямого хода на каждой
итерации для определения ведущей строки процессоры обмениваются
локально найденными максимальными значениями в столбце с
исключаемой переменной. Выполнение данного действия одновременно
с определением среди собираемых величин наибольшего значения
может быть обеспечено при помощи операции обобщенной редукции
(функция MPI_Allreduce библиотеки log2p шагов, что с учетом количества
итераций позволяет оценить время, необходимое для проведения
операций редукции, при помощи следующего выражения:$$T_p^1(comm)=(n-1)\cdot\log_2p\cdot(\alpha+w/ \beta) ,$$
где, как и ранее, $$\alpha$$ – латентность сети передачи данных, $$\beta$$ – пропускная способность сети, w – размер пересылаемого
элемента данных.
Далее также на каждой итерации прямого хода метода Гаусса
выполняется рассылка выбранной ведущей строки. Сложность данной
При выполнении обратного хода
В итоге, с учетом всех полученных выражений, трудоемкость параллельного варианта метода Гаусса составляет:$$T_p = \frac1p \sum_{i=2}^n (3i+2i^2)\tau + (n-1)\cdot\log_2 p\cdot(3\alpha+w(n+2)/ \beta),$$ где $$\tau$$ есть время выполнения базовой вычислительной операции.
Рассмотрим возможный вариант параллельной реализации метода
Гаусса для
1. Главная функция программы. Реализует логику работы алгоритма, последовательно вызывает необходимые подпрограммы.
// Программа 8.1. — Алгоритм Гаусса решения систем линейных уравнений
int ProcNum; // Число доступных процессоров
int ProcRank; // Ранг текущего процессора
int *pParallelPivotPos; // Номера строк, которые были выбраны ведущими
int *pProcPivotIter; // Номера итераций, на которых строки
// процессора использовались в качестве ведущих
void main(int argc, char* argv[]) {
double* pMatrix; // Матрица линейной системы
double* pVector; // Вектор правых частей линейной системы
double* pResult; // Вектор неизвестных
double *pProcRows; // Строки матрицы A
double *pProcVector; // Блок вектора b
double *pProcResult; // Блок вектора x
int Size; // Размер матрицы и векторов
int RowNum; // Количество строк матрицы
double start, finish, duration;
setvbuf(stdout, 0, _IONBF, 0);
MPI_Init ( argc, argv );
MPI_Comm_rank ( MPI_COMM_WORLD, ProcRank );
MPI_Comm_size ( MPI_COMM_WORLD, ProcNum );
if (ProcRank == 0)
printf("Параллельный метод Гаусса для решения систем линейных уравнений\n");
// Выделение памяти и инициализация данных
ProcessInitialization(pMatrix, pVector, pResult,
pProcRows, pProcVector, pProcResult, Size, RowNum);
// Распределение исходных данных
DataDistribution(pMatrix, pProcRows, pVector, pProcVector,
Size, RowNum);
// Выполнение параллельного алгоритма Гаусса
ParallelResultCalculation(pProcRows, pProcVector, pProcResult, Size,
RowNum);
// Сбор найденного вектора неизвестных на ведущем процессе
ResultCollection(pProcResult, pResult);
// Завершение процесса вычислений
ProcessTermination(pMatrix, pVector, pResult, pProcRows,
pProcVector, pProcResult);
MPI_Finalize();
}
Следует пояснить использование дополнительных массивов.
Элементы массива pParallelPivotPos определяют номера строк
матрицы, выбираемых в качестве ведущих, по итерациям прямого хода
метода Гаусса. Именно в этом порядке должны выполняться затем
итерации обратного хода для определения значений неизвестных pParallelPivotPos является
глобальным, и любое его изменение в одном из процессов требует
выполнения операции рассылки измененных данных всем остальным
процессам программы.
Элементы массива pProcPivotIter определяют номера итераций
прямого хода метода Гаусса, на которых строки процесса
использовались в качестве ведущих (т.е. строка i процесса
выбиралась ведущей на итерации pProcPivotIter[i] ). Начальное
значение элементов массива устанавливается нулевым, и, тем самым,
нулевое значение элемента массива pProcPivotIter[i] является
признаком того, что строка i процесса все еще подлежит обработке.
Кроме того, важно отметить, что запоминаемые в элементах массива pProcPivotIter номера итераций дополнительно означают и номера
неизвестных, для определения которых будут использованы
соответствующие строки уравнения. Массив pProcPivotIter является
локальным для каждого процесса.
Функция ProcessInitialization определяет исходные
данные решаемой задачи (число неизвестных), выделяет память для
хранения данных, осуществляет ввод матрицы коэффициентов
Функция DataDistribution реализует распределение
матрицы линейной системы и вектора правых частей между
процессорами вычислительной системы.
Функция ResultCollection осуществляет сбор со
всех процессов отдельных частей вектора неизвестных.
Функция ProcessTermination выполняет необходимый
вывод результатов решения задачи и освобождает всю ранее
выделенную память для хранения данных.
Реализация всех перечисленных функций может быть выполнена по аналогии с ранее рассмотренными примерами и предоставляется читателю в качестве самостоятельного упражнения.
2. Функция ParallelResultCalculation. Реализует
логику работы параллельного
// Функция для параллельного выполнения метода Гаусса
void ParallelResultCalculation (double* pProcRows,
double* pProcVector, double* pProcResult, int Size, int RowNum) {
ParallelGaussianElimination (pProcRows, pProcVector, Size,
RowNum);
ParallelBackSubstitution (pProcRows, pProcVector, pProcResult,
Size, RowNum);
}
3. Функция ParallelGaussianElimination. Функция
выполняет параллельный вариант прямого хода
// Функция для параллельного выполнения прямого хода метода Гаусса
void ParallelGaussianElimination (double* pProcRows,
double* pProcVector, int Size, int RowNum) {
double MaxValue; // Значение ведущего элемента на процессоре
int PivotPos; // Положение ведущей строки в полосе линейной
// системы даннного процессора
// Структура для выбора ведущего элемента
struct { double MaxValue; int ProcRank; } ProcPivot, Pivot;
// pPivotRow используется для хранения ведущей строки матрицы и
// соответствующего элемента вектора b
double* pPivotRow = new double [Size+1];
// Итерации прямого хода метода Гаусса
for (int i=0; i<Size; i++) {
// Нахождение ведущей строки среди строк процесса
double MaxValue = 0;
for (int j=0; j<RowNum; j++) {
if ((pProcPivotIter[j] == -1)
(MaxValue < fabs(pProcRows[j*Size+i]))) {
MaxValue = fabs(pProcRows[j*Size+i]);
PivotPos = j;
}
}
ProcPivot.MaxValue = MaxValue;
ProcPivot.ProcRank = ProcRank;
// Нахождение ведущего процесса (процесса, который содержит
// максимальное значение переменной MaxValue)
MPI_Allreduce(ProcPivot, Pivot, 1, MPI_DOUBLE_INT,
MPI_MAXLOC, MPI_COMM_WORLD);
// Рассылка ведущей строки
if ( ProcRank == Pivot.ProcRank ){
pProcPivotIter[PivotPos]= i; // номер итерации
pParallelPivotPos[i]= pProcInd[ProcRank] + PivotPos;
}
MPI_Bcast(pParallelPivotPos[i], 1, MPI_INT, Pivot.ProcRank,
MPI_COMM_WORLD);
if ( ProcRank == Pivot.ProcRank ){
// заполнение ведущей строки
for (int j=0; j<Size; j++) {
pPivotRow[j] = pProcRows[PivotPos*Size + j];
}
pPivotRow[Size] = pProcVector[PivotPos];
}
MPI_Bcast(pPivotRow, Size+1, MPI_DOUBLE, Pivot.ProcRank,
MPI_COMM_WORLD);
ParallelEliminateColumns(pProcRows, pProcVector, pPivotRow,
Size, RowNum, i);
}
}
Функция ParallelEliminateColumns проводит
вычитание ведущей строки из строк процесса, которые еще не
использовались в качестве ведущих (т.е. для которых элементы
массива pProcPivotIter равны нулю).
4. Функция ParallelBackSubstitution.
Функция реализует параллельный вариант обратного хода Гаусса.
// Функция для параллельного выполнения обратного хода метода Гаусса
void ParallelBackSubstitution (double* pProcRows, double* pProcVector,
double* pProcResult, int Size, int RowNum) {
int IterProcRank; // Ранг процессора, который содержит ведущую строку
int IterPivotPos; // Положение ведущей строки в полосе процессора
double IterResult; // Вычисленное значение очередной неизвестной
double val;
// Итерации обратного хода метода Гаусса
for (int i=Size-1; i>=0; i--) {
// Вычисление ранга процессора, который содержит ведущую строку
FindBackPivotRow(pParallelPivotPos[i], Size, IterProcRank,
IterPivotPos);
// Вычисление значения неизвестной
if (ProcRank == IterProcRank) {
IterResult = pProcVector[IterPivotPos]/pProcRows[IterPivotPos*Size+i];
pProcResult[IterPivotPos] = IterResult;
}
// Рассылка значения очередной неизвестной
MPI_Bcast(IterResult, 1, MPI_DOUBLE, IterProcRank, MPI_COMM_WORLD);
// Обновление вектора правых частей
for (int j=0; j<RowNum; j++)
if ( pProcPivotIter[j] < i ) {
val = pProcRows[j*Size + i] * IterResult;
pProcVector[j]=pProcVector[j] - val;
}
}
}
Функция FindBackPivotRow определяет строку, из
которой можно вычислить значение очередного элемента
результирующего вектора. Номер этой строки хранится в массиве pParallelPivotIter. По номеру функция FindBackPivotRow определяет
номер процесса, на котором эта строка хранится, и номер этой
строки в полосе pProcRows этого процесса.
Эксперименты производились на вычислительном кластере
Нижегородского университета на базе процессоров Intel Xeon 4
Для оценки длительности $$\tau$$ базовой скалярной операции
проводилось b соответственно 47 мкс и 53,29 Мбайт/с.
Все вычисления производились над числовыми значениями типа double, т.е. величина w равна 8 байт.
Результаты
| Размер матрицы | Последовательный алгоритм | Параллельный алгоритм | |||||
|---|---|---|---|---|---|---|---|
| 2 процессора | 4 процессора | 8 процессоров | |||||
| Время | Ускорение | Время | Ускорение | Время | Ускорение | ||
| 500 | 0,36 | 0,3302 | 1,0901 | 0,5170 | 0,6963 | 0,7504 | 0,4796 |
| 1000 | 3,313 | 1,5950 | 2,0770 | 1,6152 | 2,0511 | 1,8715 | 1,7701 |
| 1500 | 11,437 | 4,1788 | 2,7368 | 3,8802 | 2,9474 | 3,7567 | 3,0443 |
| 2000 | 26,688 | 9,3432 | 2,8563 | 7,2590 | 3,6765 | 7,3713 | 3,6204 |
| 2500 | 50,125 | 16,9860 | 2,9509 | 11,9957 | 4,1785 | 11,6530 | 4,3014 |
| 3000 | 85,485 | 28,4948 | 3,0000 | 19,1255 | 4,4696 | 17,6864 | 4,8333 |
(рис 8.3) Зависимость ускорения от количества процессоров при выполнении параллельного алгоритма Гаусса для разных размеров систем линейных уравненийСравнение времени выполнения эксперимента $$T^*_p$$ и теоретической
оценки Tp из (8.5) приведено в
таблице 8.2 и на рис. 8.4.
| Размер матрицы | 2 процессора | 4 процессора | 8 процессоров | |||
|---|---|---|---|---|---|---|
| $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | |
| 500 | 0,2393 | 0,3302 | 0,2819 | 0,5170 | 0,3573 | 0,7504 |
| 1000 | 1,3373 | 1,5950 | 1,1066 | 1,6152 | 1,1372 | 1,8715 |
| 1500 | 4,0750 | 4,1788 | 2,8643 | 3,8802 | 2,5345 | 3,7567 |
| 2000 | 9,2336 | 9,3432 | 5,9457 | 7,2590 | 4,7447 | 7,3713 |
| 2500 | 17,5941 | 16,9860 | 10,7412 | 11,9957 | 7,9628 | 11,6530 |
| 3000 | 29,9377 | 28,4948 | 17,6415 | 19,1255 | 12,3843 | 17,6864 |
Рассмотрим теперь совершенно иной подход к x*
системы Ax=b строится последовательность приближенных решений x0,
x1, ..., xk, ... При этом процесс вычислений организуется таким
способом, что каждое очередное приближение дает оценку точного
решения со все уменьшающейся погрешностью, и при продолжении
расчетов оценка точного решения может быть получена с любой
требуемой точностью. Подобные
(рис 8.4) График зависимости экспериментального и теоретического времени проведения эксперимента на двух процессорах от объема исходных данныхОдним из наиболее известных
Напомним, что матрица А является симметричной, если она
совпадает со своей транспонированной матрицей, т.е. А=АТ. Матрица А называется положительно определенной, если для любого вектора x
справедливо: xTAx>0.
Известно (см., например, [, ]), что после выполнения n
итераций алгоритма ( n есть порядок решаемой
Если матрица A симметричная и положительно определенная, то
функция$$q(x)=\frac12 x^T \cdot A \cdot x - x^T b+c$$
имеет единственный минимум, который достигается в точке x*,
совпадающей с q(x).
Итерация
Тем самым, новое значение приближения xk вычисляется с учетом
приближения, построенного на предыдущем шаге xk-1, скалярного
шага sk и вектора направления dk.
Перед выполнением первой итерации векторы x0 и d0 полагаются
равными нулю, а для вектора g0 устанавливается значение, равное - b. Далее каждая итерация для вычисления очередного значения
приближения xk включает выполнение четырех шагов:
Шаг 1: Вычисление градиента:$$g^k=A\cdot x^{k-1}-b;$$
Шаг 2: Вычисление вектора направления:$$d^k=-g^k+\frac{((g^k)^T,g^k)}{((g^{k-1})^T,g^{k-1})}d^(k-1),$$
где (gT,g) есть скалярное произведение векторов.
Шаг 3: Вычисление величины смещения по выбранному направлению:$$s^k=\frac{(d^k,g^k)}{(d^k)^T\cdot A\cdot d^k}$$
Шаг 4: Вычисление нового приближения:$$x^k = x^{k-1}+s^k d^k$$
Как можно заметить, данные выражения включают две операции умножения матрицы на вектор, четыре операции скалярного произведения и пять операций над векторами. Как результат, общее количество операций, выполняемых на одной итерации, составляет
t1=2n2+13n.
Как уже отмечалось ранее, для нахождения точного O(n3).
Поясним выполнение
3x0 -x1 = 3, -x0 +3x1 = 7.
Эта система уравнений второго порядка обладает симметричной положительно определенной матрицей, для нахождения точного решения этой системы достаточно провести всего две итерации метода.
На первой итерации было получено значение градиента g1=(-3,-7), значение вектора направления d1=(3, 7), значение величины
смещения s1=0,439. Соответственно, очередное приближение к
точному решению системы x1=(1,318, 3,076).
На второй итерации было получено значение градиента g2=(-2,121, 0,909), значение вектора направления d2=(2,397, -0,266),
а величина смещения – s2=0,284. Очередное приближение совпадает с
точным решением системы x2=(2, 3).
На рис. 8.5 представлена последовательность приближений к
точному решению, построенная x0 выбрана точка (0,0) ).
(рис 8.5) Итерации метода сопряженных градиентов при решении системы второго порядка
При разработке параллельного варианта метода сопряженных
градиентов для
Анализ соотношений (8.8) – (8.11) показывает, что основные
вычисления, выполняемые в соответствии с методом, состоят в
умножении матрицы A на векторы x и d, и, как результат, при
организации параллельных вычислений может быть полностью
использован материал, изложенный в лекции 6.
Дополнительные вычисления в (8.8) – (8.11), имеющие меньший
порядок сложности, представляют собой различные операции
обработки векторов (скалярное произведение, сложение и вычитание,
умножение на скаляр). Организация таких вычислений, конечно же,
должна быть согласована с выбранным параллельным способом
выполнения операции умножения матрицы на вектор. Общие же
рекомендации могут состоять в следующем: при малом размере
векторов можно применить дублирование векторов между
процессорами, при большом порядке решаемой
Выберем для дальнейшего анализа эффективности получаемых
параллельных вычислений параллельный алгоритм матрично-векторного
умножения при ленточном
Трудоемкость последовательного
Определим время выполнения параллельной реализации
Как результат, при условии дублирования всех вычислений над
векторами общая вычислительная сложность параллельного варианта
С учетом полученных оценок показатели ускорения и эффективности параллельного алгоритма могут быть выражены при помощи соотношений:$$S_p=\frac{2n^3+13n^2}{n(2\lceil n/p\rceil\cdot(2n-1)+13n)}, \quad E_p=\frac{2n^3+13n^2}{p\cdot n(2\lceil n/p\rceil\cdot(2n-1)+13n)}$$
Рассмотрев построенные показатели, можно отметить, что балансировка вычислительной нагрузки между процессорами в целом является достаточно равномерной.
Уточним теперь приведенные выражения – учтем длительность
выполняемых вычислительных операций и оценим трудоемкость w есть размер элемента упорядочиваемых данных
в байтах.
Окончательно, время выполнения параллельного варианта
Результаты
| Размер матрицы | Последовательный алгоритм | Параллельный алгоритм | |||||
|---|---|---|---|---|---|---|---|
| 2 процессора | 4 процессора | 8 процессоров | |||||
| Время | Ускорение | Время | Ускорение | Время | Ускорение | ||
| 500 | 0,5 | 0,4634 | 1,0787 | 0,4706 | 1,0623 | 1,3020 | 0,3840 |
| 1000 | 8,14 | 3,9207 | 2,0761 | 3,6354 | 2,2390 | 3,5092 | 2,3195 |
| 1500 | 31,391 | 17,9505 | 1,7487 | 14,4102 | 2,1783 | 20,2001 | 1,5539 |
| 2000 | 92,36 | 51,3204 | 1,7996 | 40,7451 | 2,2667 | 37,9319 | 2,4348 |
| 2500 | 170,549 | 125,3005 | 1,3611 | 85,0761 | 2,0046 | 87,2626 | 1,9544 |
| 3000 | 363,476 | 223,3364 | 1,6274 | 146,1308 | 2,4873 | 134,1359 | 2,7097 |
(рис 8.6) Зависимость ускорения от количества процессоров при выполнении параллельного метода сопряженных градиентов для решения систем линейных уравненийСравнение времени выполнения эксперимента $$T^*_p$$ и теоретической
оценки Tp из (8.13) приведено в таблице 8.4 и на рис. 8.7.
| Размер матрицы | 2 процессора | 4 процессора | 8 процессоров | |||
|---|---|---|---|---|---|---|
| $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | |
| 500 | 1,3042 | 0,4634 | 0,6607 | 0,4706 | 0,3390 | 1,3020 |
| 1000 | 10,3713 | 3,9207 | 5,2194 | 3,6354 | 2,6435 | 3,5092 |
| 1500 | 17,9505 | 17,5424 | 14,4102 | 8,8470 | 20,2001 | 34,9333 |
| 2000 | 82,7220 | 51,3204 | 41,4954 | 40,7451 | 20,8822 | 37,9319 |
| 2500 | 161,4695 | 125,3005 | 80,9446 | 85,0761 | 40,6823 | 87,2626 |
| 3000 | 278,9077 | 223,3364 | 139,7560 | 146,1308 | 70,1801 | 134,1359 |
(рис 8.7) График зависимости экспериментального и теоретического времени проведения эксперимента на четырех процессорах от объема исходных данных
Данная лекция посвящена проблеме параллельных вычислений при
Параллельный вариант метода Гаусса (подраздел 8.2)
основывается на ленточном разделении матрицы между процессорами с
использованием циклической схемы распределения строк, что
позволяет сбалансировать вычислительную нагрузку. Для определения
параллельного варианта метода проводится полный цикл
проектирования – определяются базовые подзадачи, выделяются
информационные взаимодействия, обсуждаются вопросы
масштабирования, выводятся оценки показателей эффективности,
предлагается схема
Важный момент при рассмотрении параллельного варианта
(рис 8.8) Ускорение параллельных алгоритмов решения системы линейных уравнений с размером матрицы 3000x3000
Проблема численного
При рассмотрении вопросов
Матрицы коэффициентов
n неизвестными x0, x1, ѕ, xn-1 может быть
определено при помощи выражения$$a_0 x_0 + a_1 x_1 + \ldots + a_{n-1} x_{n-1} = b$$
где величины a0,a1,...,an-1
и b представляют собой постоянные значения.
Множество из n
Ax = b,
где A=(ai,j) есть вещественная матрица размера nxn, а векторы b и x состоят из n элементов.
Под задачей А и вектора b обычно понимается нахождение значения
вектора неизвестных x, при котором выполняются все уравнения
системы.
Метод Гаусса – широко известный прямой алгоритм А посредством эквивалентных
преобразований (не меняющих решение системы (8.2)) к треугольному
виду, после чего значения искомых неизвестных могут быть получены
непосредственно в явном виде.
В подразделе дается общая характеристика метода Гаусса,
достаточная для начального понимания алгоритма и позволяющая
рассмотреть возможные способы параллельных вычислений при
Метод Гаусса основывается на возможности выполнения
преобразований
Метод Гаусса включает последовательное выполнение двух этапов.
На первом этапе – прямой ход метода Гаусса – исходная
Ux=c,
где матрица коэффициентов получаемой системы имеет вид$$U= \begin{pmatrix} u_{0,0} u_{0,1} \ldots u_{0, n-1} \\ 0 u_{1,1} \ldots u_{1, n-1} \\ \ldots \\ 0 0 \ldots u_{n-1,n-1} \end{pmatrix} .$$
На обратном ходе метода Гаусса (второй этап алгоритма)
осуществляется определение значений неизвестных. Из последнего
уравнения преобразованной системы может быть вычислено значение
переменной xn-1, после этого из предпоследнего уравнения
становится возможным определение переменной xn-2 и т.д.
Прямой ход метода Гаусса состоит в последовательном исключении
неизвестных в уравнениях решаемой i, 0<=i<n-1, метода производится исключение неизвестной i для всех уравнений с номерами k, большими i (т.е. i<k<=n-1 ).
Для этого из этих уравнений осуществляется вычитание строки i,
умноженной на константу ( aki/aii ), с тем чтобы результирующий
коэффициент при неизвестной xi в строках оказался нулевым – все
необходимые вычисления могут быть определены при помощи
соотношений:$$\left\phantom{(}
\begin{aligned}
a'_{kj} = a_{kj}-(a_{kj} / a_{ii})\cdot a_{ij}, \\
b'_k = b_k-(a_{kj} / a_{ii})\cdot b_i,
\end{aligned}
\right.
\quad i \le j \le n-1, \; i < k \le n-1, \; 0 \le i < n-1$$
(следует отметить, что аналогичные вычисления выполняются и над
вектором b ).
Поясним выполнение прямого хода метода Гаусса на примере
На первой итерации производится исключение неизвестной x0 из второй и третьей строки. Для этого из этих строк нужно вычесть первую строку, умноженную соответственно на 2 и 1. После этих преобразований система уравнений принимает вид:$$\begin{aligned} x_0 + 3x_1 + 2x_2=\phantom{0}1, \\ x_1 + \phantom{0}x_2 =16, \\ x_1 + 4x_2 = 25. \end{aligned}$$
В результате остается выполнить последнюю итерацию и исключить
неизвестную x1 из третьего уравнения. Для этого необходимо
вычесть вторую строку, и в окончательной форме система имеет
следующий вид:$$\begin{aligned}
x_0 + 3x_1 + 2x_2=\phantom{0}1, \\
x_1 + \phantom{0}x_2 =16, \\
3x_2 = 9.
\end{aligned}$$
На рис. 8.1 представлена общая схема состояния данных на i -й
итерации прямого хода i, уже являются нулевыми. На i -й итерации прямого хода метода
Гаусса осуществляется обнуление коэффициентов столбца i,
расположенных ниже главной диагонали, путем вычитания строки i,
умноженной на нужную ненулевую константу. После проведения (n-1)
подобной итерации матрица, определяющая
(рис 8.1) Итерация прямого хода алгоритма ГауссаПри выполнении прямого хода метода Гаусса строка, которая
используется для исключения неизвестных, носит наименование ведущей, а диагональный элемент ведущей строки называется ведущим
элементом. Как можно заметить, выполнение вычислений является
возможным только, если ведущий элемент имеет ненулевое значение.
Более того, если ведущий элемент ai,i имеет малое значение, то
деление и умножение строк на этот элемент может приводить к
накоплению вычислительной погрешности и вычислительной
неустойчивости алгоритма.
Возможный способ избежать подобной проблемы может состоять в следующем: при выполнении каждой очередной итерации прямого хода метода Гаусса следует определить коэффициент с максимальным значением по абсолютной величине в столбце, соответствующем исключаемой неизвестной, т.е.$$y=\max_{i\le k\le n-1} |a_{ki}|$$ и выбрать в качестве ведущей строку, в которой этот коэффициент располагается (данная схема выбора ведущего значения носит наименование метода главных элементов).
Вычислительная сложность прямого хода O(n3).
После приведения матрицы коэффициентов к верхнему треугольному
виду становится возможным определение значений неизвестных. Из
последнего уравнения преобразованной системы может быть вычислено
значение переменной xn-1, после этого из предпоследнего уравнения
становится возможным определение переменной xn-2 и т.д. В общем
виде выполняемые вычисления при обратном ходе метода Гаусса могут
быть представлены при помощи соотношений:$$\begin{aligned}
x_{x-1} = b_{n-1} / a_{n-1,n-1}, \\
x_i =(b_i - \sum_{j=i+1}^{n-1} a_{ij}x_j)/a_{ii}, \;
i=n-2,n-3,\ldots,0.
\end{aligned}$$
Поясним, как и ранее, выполнение обратного хода метода Гаусса
на примере рассмотренной в п. 8.2.1.1
Из последнего уравнения системы можно определить, что
неизвестная x2 имеет значение 3. В результате становится
возможным разрешение второго уравнения и определение значение
неизвестной x1=13, т.е.$$\begin{aligned}
x_0 + 3x_1 + 2x_2=\phantom{0}1, \\
x_1\;\; \phantom{+ 0x_2} =13, \\
x_2 = \phantom{0}3.
\end{aligned}$$
На последней итерации обратного хода метода Гаусса
определяется значение неизвестной x0, равное -44.
С учетом последующего параллельного выполнения можно отметить,
что вычисление получаемых значений неизвестных может выполняться
сразу во всех уравнениях системы (и эти действия могут
выполняться в уравнениях одновременно и независимо друг от
друга). Так, в рассматриваемом примере после определения значения
неизвестной x2 система уравнений может быть приведена к виду$$\begin{aligned}
x_0 + 3x_1 \phantom{+ 2x_2}=-5, \\
x_1\;\; \phantom{+ 0x_2} =13, \\
x_2 = \phantom{0}3.
\end{aligned}$$
Вычислительная сложность обратного хода O(n2).
При внимательном рассмотрении метода Гаусса можно заметить,
что все вычисления сводятся к однотипным вычислительным операциям
над строками матрицы коэффициентов A и соответствующего
элемента вектора b.
Рассмотрим общую схему параллельных вычислений и возникающие при этом информационные зависимости между базовыми подзадачами.
Для выполнения прямого хода метода Гаусса необходимо
осуществить (n-1) итерацию по исключению неизвестных для
преобразования матрицы коэффициентов A к верхнему треугольному
виду.
Выполнение итерации i, 0<=i<n-1, прямого хода метода Гаусса
включает ряд последовательных действий. Прежде всего, в самом
начале итерации необходимо выбрать ведущую строку, которая при
использовании метода главных элементов определяется поиском
строки с наибольшим по абсолютной величине значением среди
элементов столбца i, соответствующего исключаемой переменной xi.
Поскольку строки матрицы A распределены по подзадачам, для поиска
максимального значения подзадачи с номерами k, k<i, должны
обменяться своими элементами при исключаемой переменной xi. После
сбора всех необходимых данных в каждой подзадаче может быть
определено, какая из подзадач содержит ведущую строку и какое
значение является ведущим элементом.
Далее для продолжения вычислений ведущая подзадача должна
разослать свою строку матрицы A и соответствующий элемент вектора b всем остальным подзадачам с номерами k, k<i. Получив ведущую
строку, подзадачи выполняют вычитание строк, обеспечивая тем
самым исключение соответствующей неизвестной xi.
При выполнении обратного хода метода Гаусса подзадачи
выполняют необходимые вычисления для нахождения значения
неизвестных. Как только какая-либо подзадача i, 0<=i<n-1,
определяет значение своей переменной xi, это значение должно быть
разослано всем подзадачам с номерами k, k<i. Далее подзадачи
подставляют полученное значение новой неизвестной и выполняют
корректировку значений для элементов вектора b.
Выделенные базовые подзадачи характеризуются одинаковой
вычислительной трудоемкостью и сбалансированным объемом
передаваемых данных. В случае когда размер матрицы, описывающей p<n ), базовые подзадачи можно
укрупнить, объединив в рамках одной подзадачи несколько строк
матрицы. Однако применение использованной в лекциях
6 и 7
последовательной схемы разделения данных для параллельного A делится на наборы (полосы) строк вида
(см. рис. 8.2):$$A=(A_0, A_2, \ldots, A_{p-1})^T, A_i = (a_{i_0}, a_{i_1}, \ldots, a_{i_{k-1}}), \;
i_j=i+jp, \; 0 \le j < k, \; k=n/p$$
(рис 8.2) Пример использования ленточной циклической схемы разделения строк матрицы между тремя процессорамиСопоставив схему разделения данных и порядок выполнения вычислений в методе Гаусса, можно отметить, что использование циклического способа формирования полос позволяет обеспечить лучшую балансировку вычислительной нагрузки между подзадачами.
Распределение подзадач между процессорами должно учитывать
характер выполняемых в методе Гаусса коммуникационных операций.
Основным видом информационного взаимодействия подзадач является
Оценим трудоемкость рассмотренного параллельного варианта
метода Гаусса. Пусть, как и ранее, n есть порядок решаемой p, p<n, обозначает число
используемых процессоров. Тем самым, матрица коэффициентов А
имеет размер nxn, и, соответственно, n/p есть размер полосы
матрицы А на каждом процессоре.
Прежде всего, несложно показать, что общее время выполнения последовательного варианта метода Гаусса составляет:
$$T_1=2n^3/3+n^2.$$Определим теперь сложность параллельного варианта метода
Гаусса. При выполнении прямого хода алгоритма на каждой итерации
для выбора ведущей строки каждый процессор должен осуществить
выбор максимального значения в столбце с исключаемой неизвестной
в пределах своей полосы. Начальный размер полос на процессорах
равен n/p, но по мере исключения неизвестных количество строк в
полосах для обработки постепенно сокращается. Текущий размер
полос приближенно можно оценить как (n-i)/p, где i, 0<=i<n-1,
есть номер выполняемой итерации прямого хода метода Гаусса. Далее
после сбора полученных максимальных значений, определения и
рассылки ведущей строки каждый процессор должен выполнить
вычитание ведущей строки из каждой строки оставшейся части строк
своей полосы матрицы A. Количество элементов строки, подлежащих
обработке, также сокращается при исключении неизвестных, и
текущее число элементов строки для вычислений оценивается
величиной (n-i). Тем самым, сложность процедуры вычитания строк
оценивается как 2x(n-i) операций (перед вычитанием ведущая строка
умножается на масштабирующую величину aik/aii ). С учетом
выполняемого количества итераций общее число операций
параллельного варианта прямого хода метода Гаусса определяется
выражением:$$T_p^1=\sum_{i=0}^{n-2}
\left[
\frac{(n-i)}{p}+\frac{(n-i)}{p}\cdot 2(n-i)
\right]
= \frac1p \sum_{i=0}^{n-2}
\left[
(n-i)+2(n-i)^2
\right] .$$
На каждой итерации обратного хода
Просуммировав полученные выражения, можно получить$$T_p=\frac1p \sum_{i=0}^{n-2} [(n-i)+2(n-i)^2] + \frac2p \sum_{i=0}^{n-2} (n-i) = \frac1p \sum_{i=0}^{n-2} [3(n-i)+2(n-i)^2] = \frac1p \sum_{i=2}^{n} (3i+2i^2) .$$
Как результат выполненного анализа, показатели ускорения и эффективности параллельного варианта метода Гаусса могут быть определены при помощи соотношений следующего вида:$$S_p = \frac{(2n^3/3+n^2)}{\frac1p \sum\limits_{i=2}^{n}(3i+2i^2)}, \quad E_p = \frac{(2n^3/3+n^2)}{\sum\limits_{i=2}^{n}(3i+2i^2)} .$$
Полученные соотношения имеют достаточно сложный вид для
оценивания. Вместе с тем можно показать, что сложность
параллельного алгоритма имеет порядок ~(2n3/3)/p, и, тем самым,
балансировка вычислительной нагрузки между процессорами в целом
является достаточно равномерной.
Дополним сформированные показатели вычислительной сложности
метода Гаусса оценкой затрат на выполнение операций передачи
данных между процессорами. При выполнении прямого хода на каждой
итерации для определения ведущей строки процессоры обмениваются
локально найденными максимальными значениями в столбце с
исключаемой переменной. Выполнение данного действия одновременно
с определением среди собираемых величин наибольшего значения
может быть обеспечено при помощи операции обобщенной редукции
(функция MPI_Allreduce библиотеки log2p шагов, что с учетом количества
итераций позволяет оценить время, необходимое для проведения
операций редукции, при помощи следующего выражения:$$T_p^1(comm)=(n-1)\cdot\log_2p\cdot(\alpha+w/ \beta) ,$$
где, как и ранее, $$\alpha$$ – латентность сети передачи данных, $$\beta$$ – пропускная способность сети, w – размер пересылаемого
элемента данных.
Далее также на каждой итерации прямого хода метода Гаусса
выполняется рассылка выбранной ведущей строки. Сложность данной
При выполнении обратного хода
В итоге, с учетом всех полученных выражений, трудоемкость параллельного варианта метода Гаусса составляет:$$T_p = \frac1p \sum_{i=2}^n (3i+2i^2)\tau + (n-1)\cdot\log_2 p\cdot(3\alpha+w(n+2)/ \beta),$$ где $$\tau$$ есть время выполнения базовой вычислительной операции.
Рассмотрим возможный вариант параллельной реализации метода
Гаусса для
1. Главная функция программы. Реализует логику работы алгоритма, последовательно вызывает необходимые подпрограммы.
// Программа 8.1. — Алгоритм Гаусса решения систем линейных уравнений
int ProcNum; // Число доступных процессоров
int ProcRank; // Ранг текущего процессора
int *pParallelPivotPos; // Номера строк, которые были выбраны ведущими
int *pProcPivotIter; // Номера итераций, на которых строки
// процессора использовались в качестве ведущих
void main(int argc, char* argv[]) {
double* pMatrix; // Матрица линейной системы
double* pVector; // Вектор правых частей линейной системы
double* pResult; // Вектор неизвестных
double *pProcRows; // Строки матрицы A
double *pProcVector; // Блок вектора b
double *pProcResult; // Блок вектора x
int Size; // Размер матрицы и векторов
int RowNum; // Количество строк матрицы
double start, finish, duration;
setvbuf(stdout, 0, _IONBF, 0);
MPI_Init ( argc, argv );
MPI_Comm_rank ( MPI_COMM_WORLD, ProcRank );
MPI_Comm_size ( MPI_COMM_WORLD, ProcNum );
if (ProcRank == 0)
printf("Параллельный метод Гаусса для решения систем линейных уравнений\n");
// Выделение памяти и инициализация данных
ProcessInitialization(pMatrix, pVector, pResult,
pProcRows, pProcVector, pProcResult, Size, RowNum);
// Распределение исходных данных
DataDistribution(pMatrix, pProcRows, pVector, pProcVector,
Size, RowNum);
// Выполнение параллельного алгоритма Гаусса
ParallelResultCalculation(pProcRows, pProcVector, pProcResult, Size,
RowNum);
// Сбор найденного вектора неизвестных на ведущем процессе
ResultCollection(pProcResult, pResult);
// Завершение процесса вычислений
ProcessTermination(pMatrix, pVector, pResult, pProcRows,
pProcVector, pProcResult);
MPI_Finalize();
}
Следует пояснить использование дополнительных массивов.
Элементы массива pParallelPivotPos определяют номера строк
матрицы, выбираемых в качестве ведущих, по итерациям прямого хода
метода Гаусса. Именно в этом порядке должны выполняться затем
итерации обратного хода для определения значений неизвестных pParallelPivotPos является
глобальным, и любое его изменение в одном из процессов требует
выполнения операции рассылки измененных данных всем остальным
процессам программы.
Элементы массива pProcPivotIter определяют номера итераций
прямого хода метода Гаусса, на которых строки процесса
использовались в качестве ведущих (т.е. строка i процесса
выбиралась ведущей на итерации pProcPivotIter[i] ). Начальное
значение элементов массива устанавливается нулевым, и, тем самым,
нулевое значение элемента массива pProcPivotIter[i] является
признаком того, что строка i процесса все еще подлежит обработке.
Кроме того, важно отметить, что запоминаемые в элементах массива pProcPivotIter номера итераций дополнительно означают и номера
неизвестных, для определения которых будут использованы
соответствующие строки уравнения. Массив pProcPivotIter является
локальным для каждого процесса.
Функция ProcessInitialization определяет исходные
данные решаемой задачи (число неизвестных), выделяет память для
хранения данных, осуществляет ввод матрицы коэффициентов
Функция DataDistribution реализует распределение
матрицы линейной системы и вектора правых частей между
процессорами вычислительной системы.
Функция ResultCollection осуществляет сбор со
всех процессов отдельных частей вектора неизвестных.
Функция ProcessTermination выполняет необходимый
вывод результатов решения задачи и освобождает всю ранее
выделенную память для хранения данных.
Реализация всех перечисленных функций может быть выполнена по аналогии с ранее рассмотренными примерами и предоставляется читателю в качестве самостоятельного упражнения.
2. Функция ParallelResultCalculation. Реализует
логику работы параллельного
// Функция для параллельного выполнения метода Гаусса
void ParallelResultCalculation (double* pProcRows,
double* pProcVector, double* pProcResult, int Size, int RowNum) {
ParallelGaussianElimination (pProcRows, pProcVector, Size,
RowNum);
ParallelBackSubstitution (pProcRows, pProcVector, pProcResult,
Size, RowNum);
}
3. Функция ParallelGaussianElimination. Функция
выполняет параллельный вариант прямого хода
// Функция для параллельного выполнения прямого хода метода Гаусса
void ParallelGaussianElimination (double* pProcRows,
double* pProcVector, int Size, int RowNum) {
double MaxValue; // Значение ведущего элемента на процессоре
int PivotPos; // Положение ведущей строки в полосе линейной
// системы даннного процессора
// Структура для выбора ведущего элемента
struct { double MaxValue; int ProcRank; } ProcPivot, Pivot;
// pPivotRow используется для хранения ведущей строки матрицы и
// соответствующего элемента вектора b
double* pPivotRow = new double [Size+1];
// Итерации прямого хода метода Гаусса
for (int i=0; i<Size; i++) {
// Нахождение ведущей строки среди строк процесса
double MaxValue = 0;
for (int j=0; j<RowNum; j++) {
if ((pProcPivotIter[j] == -1)
(MaxValue < fabs(pProcRows[j*Size+i]))) {
MaxValue = fabs(pProcRows[j*Size+i]);
PivotPos = j;
}
}
ProcPivot.MaxValue = MaxValue;
ProcPivot.ProcRank = ProcRank;
// Нахождение ведущего процесса (процесса, который содержит
// максимальное значение переменной MaxValue)
MPI_Allreduce(ProcPivot, Pivot, 1, MPI_DOUBLE_INT,
MPI_MAXLOC, MPI_COMM_WORLD);
// Рассылка ведущей строки
if ( ProcRank == Pivot.ProcRank ){
pProcPivotIter[PivotPos]= i; // номер итерации
pParallelPivotPos[i]= pProcInd[ProcRank] + PivotPos;
}
MPI_Bcast(pParallelPivotPos[i], 1, MPI_INT, Pivot.ProcRank,
MPI_COMM_WORLD);
if ( ProcRank == Pivot.ProcRank ){
// заполнение ведущей строки
for (int j=0; j<Size; j++) {
pPivotRow[j] = pProcRows[PivotPos*Size + j];
}
pPivotRow[Size] = pProcVector[PivotPos];
}
MPI_Bcast(pPivotRow, Size+1, MPI_DOUBLE, Pivot.ProcRank,
MPI_COMM_WORLD);
ParallelEliminateColumns(pProcRows, pProcVector, pPivotRow,
Size, RowNum, i);
}
}
Функция ParallelEliminateColumns проводит
вычитание ведущей строки из строк процесса, которые еще не
использовались в качестве ведущих (т.е. для которых элементы
массива pProcPivotIter равны нулю).
4. Функция ParallelBackSubstitution.
Функция реализует параллельный вариант обратного хода Гаусса.
// Функция для параллельного выполнения обратного хода метода Гаусса
void ParallelBackSubstitution (double* pProcRows, double* pProcVector,
double* pProcResult, int Size, int RowNum) {
int IterProcRank; // Ранг процессора, который содержит ведущую строку
int IterPivotPos; // Положение ведущей строки в полосе процессора
double IterResult; // Вычисленное значение очередной неизвестной
double val;
// Итерации обратного хода метода Гаусса
for (int i=Size-1; i>=0; i--) {
// Вычисление ранга процессора, который содержит ведущую строку
FindBackPivotRow(pParallelPivotPos[i], Size, IterProcRank,
IterPivotPos);
// Вычисление значения неизвестной
if (ProcRank == IterProcRank) {
IterResult = pProcVector[IterPivotPos]/pProcRows[IterPivotPos*Size+i];
pProcResult[IterPivotPos] = IterResult;
}
// Рассылка значения очередной неизвестной
MPI_Bcast(IterResult, 1, MPI_DOUBLE, IterProcRank, MPI_COMM_WORLD);
// Обновление вектора правых частей
for (int j=0; j<RowNum; j++)
if ( pProcPivotIter[j] < i ) {
val = pProcRows[j*Size + i] * IterResult;
pProcVector[j]=pProcVector[j] - val;
}
}
}
Функция FindBackPivotRow определяет строку, из
которой можно вычислить значение очередного элемента
результирующего вектора. Номер этой строки хранится в массиве pParallelPivotIter. По номеру функция FindBackPivotRow определяет
номер процесса, на котором эта строка хранится, и номер этой
строки в полосе pProcRows этого процесса.
Эксперименты производились на вычислительном кластере
Нижегородского университета на базе процессоров Intel Xeon 4
Для оценки длительности $$\tau$$ базовой скалярной операции
проводилось b соответственно 47 мкс и 53,29 Мбайт/с.
Все вычисления производились над числовыми значениями типа double, т.е. величина w равна 8 байт.
Результаты
| Размер матрицы | Последовательный алгоритм | Параллельный алгоритм | |||||
|---|---|---|---|---|---|---|---|
| 2 процессора | 4 процессора | 8 процессоров | |||||
| Время | Ускорение | Время | Ускорение | Время | Ускорение | ||
| 500 | 0,36 | 0,3302 | 1,0901 | 0,5170 | 0,6963 | 0,7504 | 0,4796 |
| 1000 | 3,313 | 1,5950 | 2,0770 | 1,6152 | 2,0511 | 1,8715 | 1,7701 |
| 1500 | 11,437 | 4,1788 | 2,7368 | 3,8802 | 2,9474 | 3,7567 | 3,0443 |
| 2000 | 26,688 | 9,3432 | 2,8563 | 7,2590 | 3,6765 | 7,3713 | 3,6204 |
| 2500 | 50,125 | 16,9860 | 2,9509 | 11,9957 | 4,1785 | 11,6530 | 4,3014 |
| 3000 | 85,485 | 28,4948 | 3,0000 | 19,1255 | 4,4696 | 17,6864 | 4,8333 |
(рис 8.3) Зависимость ускорения от количества процессоров при выполнении параллельного алгоритма Гаусса для разных размеров систем линейных уравненийСравнение времени выполнения эксперимента $$T^*_p$$ и теоретической
оценки Tp из (8.5) приведено в
таблице 8.2 и на рис. 8.4.
| Размер матрицы | 2 процессора | 4 процессора | 8 процессоров | |||
|---|---|---|---|---|---|---|
| $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | |
| 500 | 0,2393 | 0,3302 | 0,2819 | 0,5170 | 0,3573 | 0,7504 |
| 1000 | 1,3373 | 1,5950 | 1,1066 | 1,6152 | 1,1372 | 1,8715 |
| 1500 | 4,0750 | 4,1788 | 2,8643 | 3,8802 | 2,5345 | 3,7567 |
| 2000 | 9,2336 | 9,3432 | 5,9457 | 7,2590 | 4,7447 | 7,3713 |
| 2500 | 17,5941 | 16,9860 | 10,7412 | 11,9957 | 7,9628 | 11,6530 |
| 3000 | 29,9377 | 28,4948 | 17,6415 | 19,1255 | 12,3843 | 17,6864 |
Рассмотрим теперь совершенно иной подход к x*
системы Ax=b строится последовательность приближенных решений x0,
x1, ..., xk, ... При этом процесс вычислений организуется таким
способом, что каждое очередное приближение дает оценку точного
решения со все уменьшающейся погрешностью, и при продолжении
расчетов оценка точного решения может быть получена с любой
требуемой точностью. Подобные
(рис 8.4) График зависимости экспериментального и теоретического времени проведения эксперимента на двух процессорах от объема исходных данныхОдним из наиболее известных
Напомним, что матрица А является симметричной, если она
совпадает со своей транспонированной матрицей, т.е. А=АТ. Матрица А называется положительно определенной, если для любого вектора x
справедливо: xTAx>0.
Известно (см., например, [, ]), что после выполнения n
итераций алгоритма ( n есть порядок решаемой
Если матрица A симметричная и положительно определенная, то
функция$$q(x)=\frac12 x^T \cdot A \cdot x - x^T b+c$$
имеет единственный минимум, который достигается в точке x*,
совпадающей с q(x).
Итерация
Тем самым, новое значение приближения xk вычисляется с учетом
приближения, построенного на предыдущем шаге xk-1, скалярного
шага sk и вектора направления dk.
Перед выполнением первой итерации векторы x0 и d0 полагаются
равными нулю, а для вектора g0 устанавливается значение, равное - b. Далее каждая итерация для вычисления очередного значения
приближения xk включает выполнение четырех шагов:
Шаг 1: Вычисление градиента:$$g^k=A\cdot x^{k-1}-b;$$
Шаг 2: Вычисление вектора направления:$$d^k=-g^k+\frac{((g^k)^T,g^k)}{((g^{k-1})^T,g^{k-1})}d^(k-1),$$
где (gT,g) есть скалярное произведение векторов.
Шаг 3: Вычисление величины смещения по выбранному направлению:$$s^k=\frac{(d^k,g^k)}{(d^k)^T\cdot A\cdot d^k}$$
Шаг 4: Вычисление нового приближения:$$x^k = x^{k-1}+s^k d^k$$
Как можно заметить, данные выражения включают две операции умножения матрицы на вектор, четыре операции скалярного произведения и пять операций над векторами. Как результат, общее количество операций, выполняемых на одной итерации, составляет
t1=2n2+13n.
Как уже отмечалось ранее, для нахождения точного O(n3).
Поясним выполнение
3x0 -x1 = 3, -x0 +3x1 = 7.
Эта система уравнений второго порядка обладает симметричной положительно определенной матрицей, для нахождения точного решения этой системы достаточно провести всего две итерации метода.
На первой итерации было получено значение градиента g1=(-3,-7), значение вектора направления d1=(3, 7), значение величины
смещения s1=0,439. Соответственно, очередное приближение к
точному решению системы x1=(1,318, 3,076).
На второй итерации было получено значение градиента g2=(-2,121, 0,909), значение вектора направления d2=(2,397, -0,266),
а величина смещения – s2=0,284. Очередное приближение совпадает с
точным решением системы x2=(2, 3).
На рис. 8.5 представлена последовательность приближений к
точному решению, построенная x0 выбрана точка (0,0) ).
(рис 8.5) Итерации метода сопряженных градиентов при решении системы второго порядка
При разработке параллельного варианта метода сопряженных
градиентов для
Анализ соотношений (8.8) – (8.11) показывает, что основные
вычисления, выполняемые в соответствии с методом, состоят в
умножении матрицы A на векторы x и d, и, как результат, при
организации параллельных вычислений может быть полностью
использован материал, изложенный в лекции 6.
Дополнительные вычисления в (8.8) – (8.11), имеющие меньший
порядок сложности, представляют собой различные операции
обработки векторов (скалярное произведение, сложение и вычитание,
умножение на скаляр). Организация таких вычислений, конечно же,
должна быть согласована с выбранным параллельным способом
выполнения операции умножения матрицы на вектор. Общие же
рекомендации могут состоять в следующем: при малом размере
векторов можно применить дублирование векторов между
процессорами, при большом порядке решаемой
Выберем для дальнейшего анализа эффективности получаемых
параллельных вычислений параллельный алгоритм матрично-векторного
умножения при ленточном
Трудоемкость последовательного
Определим время выполнения параллельной реализации
Как результат, при условии дублирования всех вычислений над
векторами общая вычислительная сложность параллельного варианта
С учетом полученных оценок показатели ускорения и эффективности параллельного алгоритма могут быть выражены при помощи соотношений:$$S_p=\frac{2n^3+13n^2}{n(2\lceil n/p\rceil\cdot(2n-1)+13n)}, \quad E_p=\frac{2n^3+13n^2}{p\cdot n(2\lceil n/p\rceil\cdot(2n-1)+13n)}$$
Рассмотрев построенные показатели, можно отметить, что балансировка вычислительной нагрузки между процессорами в целом является достаточно равномерной.
Уточним теперь приведенные выражения – учтем длительность
выполняемых вычислительных операций и оценим трудоемкость w есть размер элемента упорядочиваемых данных
в байтах.
Окончательно, время выполнения параллельного варианта
Результаты
| Размер матрицы | Последовательный алгоритм | Параллельный алгоритм | |||||
|---|---|---|---|---|---|---|---|
| 2 процессора | 4 процессора | 8 процессоров | |||||
| Время | Ускорение | Время | Ускорение | Время | Ускорение | ||
| 500 | 0,5 | 0,4634 | 1,0787 | 0,4706 | 1,0623 | 1,3020 | 0,3840 |
| 1000 | 8,14 | 3,9207 | 2,0761 | 3,6354 | 2,2390 | 3,5092 | 2,3195 |
| 1500 | 31,391 | 17,9505 | 1,7487 | 14,4102 | 2,1783 | 20,2001 | 1,5539 |
| 2000 | 92,36 | 51,3204 | 1,7996 | 40,7451 | 2,2667 | 37,9319 | 2,4348 |
| 2500 | 170,549 | 125,3005 | 1,3611 | 85,0761 | 2,0046 | 87,2626 | 1,9544 |
| 3000 | 363,476 | 223,3364 | 1,6274 | 146,1308 | 2,4873 | 134,1359 | 2,7097 |
(рис 8.6) Зависимость ускорения от количества процессоров при выполнении параллельного метода сопряженных градиентов для решения систем линейных уравненийСравнение времени выполнения эксперимента $$T^*_p$$ и теоретической
оценки Tp из (8.13) приведено в таблице 8.4 и на рис. 8.7.
| Размер матрицы | 2 процессора | 4 процессора | 8 процессоров | |||
|---|---|---|---|---|---|---|
| $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | $$T_p$$ | $$T_p^*$$ | |
| 500 | 1,3042 | 0,4634 | 0,6607 | 0,4706 | 0,3390 | 1,3020 |
| 1000 | 10,3713 | 3,9207 | 5,2194 | 3,6354 | 2,6435 | 3,5092 |
| 1500 | 17,9505 | 17,5424 | 14,4102 | 8,8470 | 20,2001 | 34,9333 |
| 2000 | 82,7220 | 51,3204 | 41,4954 | 40,7451 | 20,8822 | 37,9319 |
| 2500 | 161,4695 | 125,3005 | 80,9446 | 85,0761 | 40,6823 | 87,2626 |
| 3000 | 278,9077 | 223,3364 | 139,7560 | 146,1308 | 70,1801 | 134,1359 |
(рис 8.7) График зависимости экспериментального и теоретического времени проведения эксперимента на четырех процессорах от объема исходных данных
Данная лекция посвящена проблеме параллельных вычислений при
Параллельный вариант метода Гаусса (подраздел 8.2)
основывается на ленточном разделении матрицы между процессорами с
использованием циклической схемы распределения строк, что
позволяет сбалансировать вычислительную нагрузку. Для определения
параллельного варианта метода проводится полный цикл
проектирования – определяются базовые подзадачи, выделяются
информационные взаимодействия, обсуждаются вопросы
масштабирования, выводятся оценки показателей эффективности,
предлагается схема
Важный момент при рассмотрении параллельного варианта
(рис 8.8) Ускорение параллельных алгоритмов решения системы линейных уравнений с размером матрицы 3000x3000
Проблема численного
При рассмотрении вопросов
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.