http://maxxk.github.io/programming-semester-6/
Рекомендуется просматривать с использованием Firefox (в дисплейных классах) или Chrome
Матрицу между процессами можно делить по строкам или по столбцам.
Обычно выгоднее всего с позиций распараллеливания делить таким образом, чтобы в той части программы, которая занимает \(O(n^3)\) операций, внутренний цикл до \(n\) выполнялся в одном процессе (т.е. параллельно выполняется цикл «второго уровня вложенности»).
Как правило (методы Гаусса, Жордана, LU, QR и вращений-отражений), это применение преобразования к оставшейся части матрицы.
for (int diag=0; diag < n; diag++) {
// Здесь может потребоваться пересылка
// Потом — вычисление какого-то параметра шага
// Потом — ещё одна пересылка
// Следующий цикл нужно распараллелить:
for (int i = diag; i < n; i++) {
// Следующий цикл должен выполняться на одном узле
// (или не иметь точек синхронизации/пересылки для элементов)
for (int k = diag; k < n; k++) {
// ...
}
}
}
Иногда для отладки требуется вывести на экран части матрицы последовательно для каждого процесса. Для этого можно использовать следующую схему:
#ifdef DEBUG // не использовать при компиляции без -DDEBUG
// size — количество процессов
// rank — номер процесса
for (int pproc = 0; pproc < size; pproc++) {
if (rank == pproc) {
printf(...); // вывести на экран
}
MPI_Barrier(MPI_COMM_WORLD);
}
#endif
Компилировать с ключом -DDEBUG
, чтобы код был активен
Проверьте для чётных и нечётных N, P; для взаимно-простых N и P. Используйте формулу \(a_{ij} = i·n+j\), тогда значение каждого элемента матрицы — его номер. Пример (N = 5, P = 3):
Матрица:
\[
\pmatrix{
0 & 1 & 2 & 3 & 4 \\
5 & 6 & 7 & 8 & 9 \\
10 & 11 & 12 & 13 & 14 \\
15 & 16 & 17 & 18 & 19 \\
20 & 21 & 22 & 23 & 24
}
\]
По процессам:
\[
\matrix{
0 & 1 & 2 \\
\pmatrix{
0 & 3 \\ 5 & 8 \\ 10 & 13 \\ 15 & 18 \\ 20 & 23
} &
\pmatrix {
1 & 4 \\ 6 & 9 \\ 11 & 14 \\ 16 & 18 \\ 21 & 24
} &
\pmatrix{
2 \\ 7 \\ 12 \\ 17 \\ 22
}
}
\]
rank == size -1
);