Уровень алгоритма

Алгоритм Ланцоша для арифметики с плавающей точкой с выборочной ортогонализацией: различия между версиями

Материал из Алговики
Перейти к навигации Перейти к поиску
[непроверенная версия][непроверенная версия]
Строка 1: Строка 1:
 
Авторы: Абдулпотиев А.А.
 
Авторы: Абдулпотиев А.А.
 +
{{Временная статья|}}
  
== Свойства и структура алгоритма ==
+
Авторы: Абдулпотиев А.А.
===Общее описание алгоритма===
 
Алгоритм Лáнцоша является мощным инструментом для решения некоторого класса больших разреженных симметричных спектральных задач <math>Ax = A^T</math>. Однако любая практическая реализация этого алгоритма страдает от ошибок округления, т.к. векторы Ланцоша теряют взаимную ортогональность. Для того чтобы поддерживать некоторый уровень ортогональности, появились методы полной переортогонализации и выборочной ортогонализации. В этой работе мы рассмотрим последний метод в качестве способа для поддержания ортогональности среди векторов Ланцоша. Он обладает почти столь же высокой точностью, как алгоритм с полной переортогонализацией, и почти столь же низкой стоимостью, как алгоритм без ортогонализации <ref>"The Lanczos Algorithm With Partial Reorthogonalization", Horst D. Simon, Mathematics of computation, volume 42, number 165, pages 115-142  (1984)</ref>.  
 
  
 +
{{algorithm
 +
| name              = Алгоритм Ланцоша для арифметики с плавающей точкой с выборочной ортогонализацией
 +
| serial_complexity = <math>O(kn^2 + k^2n)</math>
 +
| pf_height        = <math>O(kn + k^2)</math>
 +
| pf_width          = <math>O(n)</math>
 +
| input_data        = <math>n^2 + n + 1</math>
 +
| output_data      = <math>nk</math>
 +
}}
  
Дается вещественная симметричная матрица  <math>A = A^T</math>,
+
= Свойства и структура алгоритма =
{{Шаблон:ASymmetric}} <math> \, \;  (1), </math>
+
== Общее описание алгоритма ==
случайный вектор <math>b </math>, являющийся первым приближением собственного вектора матрицы, <math>k </math> - количество собственных значений и собственных векторов, которые мы хотим найти, т.е. количество итераций.
 
  
 +
Прежде чем приступить к описанию алгоритма, нужно немного рассказать о самой проблеме, которую решает алгоритм Ланцоша и понятия, которые необходимы для освоения дальнейшего материала. Кратко говоря алгоритм Ланцоша это итерационный метод нахождения небольшого количества собственных значений столь больших разреженных симметричных матриц, что к ним нельзя применить прямые методы. Иными словами алгоритм сильно оптимизирует использование памяти и вычислительной мощности, что является критически важным для больших вычислений.
  
На каждой итерации строится матрица <math>Q_j = [q_1, q_2, \dots, q_j]</math> размерности <math>n \times j</math>, состоящая из ортонормированных векторов Ланцоша <math>z</math>. В качестве приближенных собственных значений берутся числа Ритца <math>\theta_i </math>, т.е. собственные значения симметричной трехдиагональной матрицы <math>T_j = Q^T_j A Q_j</math> размерности <math>j \times j</math>.
+
Нам понадобятся сведения о крыловских подпронстранствах, симметричной проблеме собственных значений, а также о степенном методе и обратной итерации.
  
:<math>
+
Сам алгоритм объединяет метод Ланцоша для построения крыловского подпространства с процедурой Рэлея-Ритца интерпретации собственных значений некоторой вычисляемой матрицы как приближений к собственным значениям исходной матрицы.
T_j = \begin{pmatrix}
+
 
\alpha_1 & \beta_1 \\
+
Пусть <math>Q = [Q_k,Q_u]</math> - ортогональная матрица порядка <math>n</math>, причем <math>Q_k</math> и <math>Q_u</math> имеют соответственно размеры <math>n \times k</math> и <math>n \times (n-k)</math>. Столбцы матрицы <math>Q_k</math> вычисляются методом Ланцоша..
\beta_1 & \alpha_2 & \beta_2 \\
+
 
& \beta_2 & \ddots & \ddots \\
+
Запишем следующие соотношения:
& & \ddots & \ddots & \beta_{j-1} \\
+
 
& & & \beta_{j-1} & \alpha_j
+
<math>T = Q^T A Q = [Q_k, Q_u]^T A [Q_k, Q_u] =
\end{pmatrix}\; (2).
+
\left[ \begin{array}{cc}
 +
Q_k^T A Q_k & Q_k^T A Q_u\\
 +
Q_u^T A Q_k & Q_u^T A Q_u
 +
\end{array} \right]
 +
= \left[ \begin{array}{cc}
 +
T_{k} & T_{ku}^T\\
 +
T_{ku} & T_{u}
 +
\end{array} \right]</math>
 +
 
 +
Метод Рэлея-Ритца заключается в интерпретации собственных значений матрицы <math>T_k = Q_k^T A Q_k</math> как приближенных к собственным значениям матрицы <math>A</math>. Эти приближения называются числами Ритца. Если <math>A = V \Lambda V^T</math> есть спектральное разложение матрицы <math>T_k</math>, то столбцы матрицы <math>Q_k V</math> являются приближениями соответствующих собственных векторов и называются векторами Ритца.
 +
 
 +
Числа и векторы Ритца являются ''оптимальными'' приближениями к собственным значениям и собственным векторам матрицы <math>A</math>.
 +
 
 +
При применении метода Ланцоша в арифметике с плавающей точкой ортогональность в вычисленных векторах Ланцоша <math>q_k</math> пропадает из-за ошибок округления. Потеря ортогональности не заставляет алгоритм вести себя совершенно не предсказуемым образом. В самом деле, мы увидим, что цена, которую мы платим за потерю, это приобретение повторных копий сошедшихся чисел Ритца. Для того чтобы поддержать взаимную ортогональность векторов Ланцоша, существуют две модификации алгоритма.
 +
# '''Алгоритм Ланцоша с полной переортогонализацией'''. На каждой итерации запускается повторный процесс ортогонализации Грамма-Шмидта <math>z = z - \textstyle \sum_{i=1}^{j-1} (z^T q_i)q_i \displaystyle</math>
 +
# '''Алгоритм Ланцоша с выборочной ортогонализацией'''.  Согласно теореме Пейджа векторы <math>q_k</math> теряют ортогональность весьма систематическим образом, а именно, приобретая большие компоненты в направлениях уже сошедшихся векторов Ритца (Именно это приводит к появлению повторных копий сошедшихся чисел Ритца). Поэтому можно выборочно ортогонализировать векторы <math>q_k</math> вместо того, чтобы на каждом шаге ортогонализировать вектор ко всем ранее сошедшимся векторам, как это делается при полной ортогонализации. Таким образом достигается (почти) ортогональности векторов Ланцоша, затрачивая очень небольшая дополнительную работу.
 +
 
 +
== Математическое описание алгоритма ==
 +
 
 +
Пусть <math>A</math> - заданная симметричная матрица, <math>b</math> - вектор начального приближения метода Ланцоша.
 +
Тогда алгоритм Ланцоша вычисления собственных векторов и собственных значений матрицы <math>A</math> с выборочной ортогонализацией имеет следующий вид:
 +
 
 +
<math>
 +
\begin{align}
 +
q_1 = & b / \Vert b \Vert_2, \; \beta_0 = 0,\; q_0 = 0\\
 +
for \; & j = 1 \; to \; k \\
 +
& z = A\,q_j\\
 +
& \alpha_j = q_j^T z\\
 +
& z = z - \alpha_j q_j - \beta_{j-1}q_{j-1}\\
 +
& t = j-1\\
 +
& for \; i=1 \; to \; t \\
 +
& \; \; \; if \; \beta_t \|v_i (t)\| \le \sqrt{\epsilon} \Vert T_t \Vert_2 \; then\\
 +
& \; \; \; \; \; \; z = z - (y_{i,t} ^ T z) y_{i,t} \;/*\; y_{i,t} = Q_t v_i \;*/ \\
 +
& end \; for\\
 +
& \beta_j = \Vert z \Vert_2\\
 +
& if \; \beta_j = 0 \; then\\
 +
& \; \; \; Stop\; the\; algorithm\\
 +
& q_{j+1} = z / \beta_j\\
 +
& /*Calculate\; eigenvalues\; and\; eigenvektors\; of\; T_j\; */\\
 +
end \; & for
 +
\end{align}
 
</math>
 
</math>
  
Однако, векторы <math>q_j </math> теряют ортогональность вследствие приобретения больших компонент в направлениях векторов Ритца <math>y_{i,j} = Q_j v_i </math>, отвечающих сошедшимся числам Ритца <math> \theta_i </math>. Поэтому чтобы построить <math>q_j </math>, предлагается на каждом шаге следить за оценками погрешностей  <math>\beta_{t}|v_i(t)|, i = 1 \dots t, t = j - 1 </math>, где <math>v_i(t) </math> - <math>t</math>-я компонента собственного вектора <math>v_i </math>. И когда какая-то оценка становится слишком малой, проводить ортогонализацию вектора Ланцоша <math>z </math>. Величина <math>\beta_{t}|v_i(t)| </math> считается малой, если она меньше, чем <math>\sqrt{\varepsilon}||T_{t}|| </math>, где <math>\varepsilon</math> - доступная машинная точность чисел.
+
Где <math>v_i</math> - это столбцы ортогональной матрицы <math>V</math> из спектрального разложения <math>T_t = V \Lambda V^T</math>, а <math>y_{t,i} = Q_t v_i</math> - столбцы матрицы <math>Q_t V</math> - векторы Ритца.
 +
 
 +
Согласно теореме Пейджа, <math>y_{t,i}^T q_{t+1} = O(\epsilon \Vert A \Vert_2) / \beta_t \Vert v_i(t) \Vert</math>, то есть компонента <math>y_{t,i}^T q_{t+1}</math> вычисленного вектора Ланцоша <math>q_{t+1}</math> в направлении вектора Ритца <math>y_{t,i} = Q_t v_i</math> обратно пропорциональна величине <math>\beta_t \Vert v_i(t) \Vert</math>, являющейся оценкой погрешности для соответствующего числа Ритца. Поэтому, когда число Ритца сходится, а его оценка погрешности приближается к нулю, вектор Ланцоша приобретает большую компоненту в направлении вектора Ритца <math>q_{t,i}</math>, и следует произвести процедуру переортогонализации.  
 +
 
 +
Величина погрешности <math>\beta_t \Vert v_i(t) \Vert</math> считается малой, если она меньше, чем <math>\sqrt{\epsilon} \Vert A \Vert_2</math>, так как в этом случае, согласно теореме Пейджа, компонента <math>\Vert y_{i,t}^T q_{t+1} \Vert = \Vert y_{i,t}^T z \Vert / \Vert z \Vert_2</math> скорее всего превосходит уровень <math>\sqrt{\epsilon}</math> (на практике используется <math>\Vert T_t \Vert_2</math> вместо <math>\Vert A \Vert_2</math>, так как первое известно, а второе не всегда).
 +
 
 +
== Вычислительное ядро алгоритма ==
 +
 
 +
У описанного алгоритма два ядра, на которые приходится основное время работы алгоритма:
 +
 
 +
* Вычисление вектора <math>z = A q_j: O (n^2)</math> операций умножения.
 +
* Выборочная переортогонализация <math>z = z - (y_{i,t} ^ T z) y_{i,t}</math>, где <math>i = 1\dots t</math>.
 +
 
 +
== Макроструктура алгоритма ==
 +
 
 +
Макроструктура алгоритма Ланцоша с выборочной переортогонализацией представляется в виде совокупности метода Ланцоша с выборочной переортогонализацией построения крыловского подпространства и процедуры Рэлея-Ритца.
 +
 
 +
Каждая итерация первого этапа может быть разложена на следующие макроединицы:
 +
* Умножение матрицы на вектор
 +
* Вычисление скалярного произведения векторов
 +
* Умножение векторов на числа и вычитание векторов
 +
* При выполнении условия необходимости переортогонализации – перемножение и вычитание векторов
 +
* Вычисление нормы вектора
 +
* Умножение вектора на число
 +
 
 +
Второй этап, процедура Рэлея-Ритца, заключается в нахождении собственных значений и собственных векторов матрицы и интерпретации их как приближенных значений собственных чисел и собственных векторов исходной матрицы, он может быть выполнен любым способом, например, QR-итерацией.
 +
 
 +
== Схема реализации последовательного алгоритма ==
 +
 
 +
На вход алгоритму подаются исходная матрица <math>A</math>, вектор начального приближения <math>b</math> и число <math>k</math>.
 +
Далее последовательно выполняются итерационно для всех <math>j: 1 \le j \le k</math> следующие шаги:
 +
 
 +
# Умножается матрица на вектор для нахождения вектора <math>z</math>
 +
# Вычисляется коэффициент <math>\Alpha_j</math> посредством скалярного перемножения векторов
 +
# Вычисляется новое значение вектора <math>z</math>
 +
# Производятся оценка погрешностей <math>\beta_t \Vert v_i(t) \Vert</math>, где <math>t = j - 1</math> и выборочная переортогонализация
 +
# Вычисление очередного значения <math>\beta_j</math> - норма вектора <math>z</math>
 +
# Вычисление и добавление к матрице <math>Q</math> нового столбца
 +
# Вычисление собственных значений и собственных векторов матрицы <math>T_j</math>
 +
 
 +
== Последовательная сложность алгоритма ==
 +
 
 +
* Вычисление вектора <math>z</math> - <math>n^2</math> операций умножения и <math>n(n-1)</math> операций сложения
 +
* Вычисление скалярного произведения векторов - <math>n</math> операций умножения и <math>(n-1)</math> сложений
 +
* Вычисление вектора <math>z</math> - <math>2n</math> умножений и <math>2n</math> сложений
 +
* Оценка погрешностей - <math>kn</math> операций умножения
 +
* Выборочная переортогонализация - <math>O(2nj)</math> умножений и <math>O(2j(n-1) + n)</math> сложений
 +
* Вычисление нормы вектора - <math>n</math> операций умножения и <math>(n-1)</math> сложений
 +
* Вычисление нового столбца матрицы <math>Q</math> - <math>n</math> операций умножения
 +
 
 +
Итого на каждой итерации:
 +
 
 +
* Умножений: <math>n^2 + n + 2n + kn + O(2nj) + n + n = n^2 + 5n + kn + O(2nj)</math>
 +
* Сложений: <math>n(n-1) + n-1 + 2n + O(2j(n-1) + n) + n-1 = n^2 + 3n + O(2j(n-1) + n) -2</math>
 +
 
 +
Итого за все время выполнения алгоритма:
  
 +
* Умножений: <math>kn^2 + 5kn + k^2n + O(k^2n + kn)</math>
 +
* Сложений: <math>kn^2 + 3kn + O((k^2+k)(n-1)+kn) = kn^2 + 3kn + O(k^2(n-1)+2kn-k)</math>
  
После следует вычисление собственных значений  <math> \theta_j </math> и собственных векторов <math>v_j </math> полученной трехдиагональной матрицы <math>T_j</math>, для чего существует, например, метод "разделяй и властвуй"<ref>Дж. Деммель «Вычислительная линейная алгебра», c. 232, алгоритм 5.2</ref>
+
Суммарная последовательная сложность алгоритма - <math>O(kn^2 + k^2n)</math>.
  
=== Математическое описание алгоритма ===
+
== Информационный граф ==
<math> \beta_0=0,q_0=0</math>
 
<math> q_{1} = \frac{b_{j}}{\|b\|_2}</math>, где <math> \|b\|_2 = \sqrt{\sum\limits_{j=1}^{n} b_j^2}</math>
 
<math> for\, j=1\,\, to\, \, k\, \, do:</math>
 
    <math>z=Aq_j,  </math>
 
    <math>\alpha_j=q_j^Tz, </math>
 
    <math>z=z-\alpha_jq_j-\beta_{j-1}q_{j-1},  </math>
 
    <math>t = j - 1,  </math>
 
    <math>for\, i=1\,\, to\, \, t\, \, do: </math>
 
        <math>if\,  \beta_{t}|v_i(t)| \leqslant \sqrt{\varepsilon}\|T_{t}\| \, \,  then:</math>
 
            <math>z = z-(y^T_{i,t},z)y_{i,t} </math>, где <math>y_{i,t} = Q_{t}v_i</math>
 
    <math>\beta_{j}=\|z\|_2 </math>
 
    <math>q_{j+1}=z/\beta_{j}, </math>
 
    Строим матрицу  <math> T_j</math> (2), вычисляем собственные значения  <math> \theta_j </math> и собственные векторы <math>v_j </math> полученной матрицы <math>T_j</math>.
 
  
=== Вычислительное ядро алгоритма ===
+
Ниже представлен граф одной итерации алгоритма с разделением на <math>n</math> потоков.
Выделены следующие вычислительные ядра:
 
  
* Умножение матрицы на вектор, <math>z=Aq_j,  </math>.  
+
[[Файл:Algorithm_scheme_(v._3).svg|1350px|thumb|center| Рисунок 1. Детальный граф алгоритма Ланцоша с выборочной переортогонализацией.<br><br>
 +
Oper - простая операция сложения/вычитания/умножения/деления с числами с плавающей точкой.<br>
 +
'?' - проверка условия на необходимость переортогонализации.<br><br>
 +
На вход итерации подается матрица <math>A</math> и вектор <math>q_j</math>, на выходе получаем новый вектор <math>q_{j+1}</math>.]]
  
  
* Ортогонализация по отношению к сошедшимся векторам  <math>z = z-(y^T_{i,t},z)y_{i,t} </math> для <math>i  = 1 \dots t</math>
+
== Ресурс параллелизма алгоритма ==
  
 +
На каждой из итераций алгоритма можно получить выигрыш за счет распараллеливания следующих шагов:
  
===Макроструктура алгоритма===
+
* Вычисление вектора <math>z</math> - умножение матрицы размера <math>n \times n</math> на вектор длины <math>n</math> - <math>n</math> ярусов сложений, <math>n</math> операций умножений в каждом
Были выделены следующие макрооперации:
+
* Вычисление коэффициента <math>\alpha_j</math> - скалярное произведение векторов - <math>n</math> ярусов сложений, 1 операция умножения в каждом
 +
* Вычисление нового значения вектора <math>z</math>: 2 яруса умножений длины <math>n</math> (умножение вектора на число), 2 яруса вычитаний длины <math>n</math>
 +
* Выборочная переортогонализация: последовательно для всех <math>i \le k</math> выполняется <math>j</math> ярусов сложений, <math>n</math> операций умножений в каждом, <math>n</math> ярусов сложений, <math>j</math> операций умножений в каждом, один ярус вычитаний размера <math>n</math>
 +
* Вычисление <math>\beta_j</math> - скалярное произведение векторов - <math>n</math> ярусов сложений, 1 операция умножения в каждом
 +
* Вычисление <math>q_j</math> - деление вектора на число - один ярус делений размера <math>n</math>
  
1. Умножение матрицы на вектор,
+
Сложность алгоритма по ширине ЯПФ - <math>O(n)</math>.
  
<math>z=Aq_j,  </math>.
+
== Входные и выходные данные алгоритма ==
  
2. Вычисление вектора <math>q_{j+1} </math> с помощью линейной комбинации других векторов:
+
Входные данные: вещественная матрица <math>A</math> размера <math>n \times n</math>, вектор <math>b</math> длины <math>n</math>, число <math>k</math>
  
<math>\alpha_j=q_j^Tz, </math>
+
Объем входных данных: <math>n^2 + n + 1</math>
  
<math>z=z-\alpha_jq_j-\beta_{j-1}q_{j-1},  </math>
+
Выходные данные: матрица <math>Q</math> размера <math>n \times k</math>
  
<math>q_{j+1}=z/\|z\|_2</math>
+
Объем выходных данных: <math>nk</math>
  
3. Ортогонализация вектора Ланцоша с помощью скалярного произведения: 
+
== Свойства алгоритма ==
  
<math>z = z-(y^T_{i,t},z)y_{i,t} </math>
+
* Соотношение последовательной и параллельной сложности алгоритма равно <math>n</math>, что говорит о том, что параллельная реализация теоретически должна давать ощутимый выигрыш
 +
* Вычислительная мощность алгоритма - отношение числа операций к суммарному объему входных и выходных данных - примерно равно <math>2k</math>
 +
* Алгоритм устойчив, так как операция переортогонализации как раз направлена на исключение проблемы округления вычисляемых значений
 +
* Алгоритм не является детерминированным, так как, во-первых, используется для разряженных матриц, и, во-вторых, является итерационным с выходом по точности - число операций заранее не определено
 +
* Алгоритм содержит длинные дуги, так как на протяжении всего процесса его выполнения нужно хранить исходную матрицу <math>A</math> и матрицу <math>Q</math> - они нужны на каждой итерации
  
4. Для вычисления собственных значений матрицы будет использоваться алгоритм "разделяй и властвуй".
+
= Программная реализация алгоритма =
  
===Схема реализации последовательного алгоритма===
+
== Особенности реализации последовательного алгоритма ==
  
<math>1)</math> Инициализируются векторы <math> \beta_0=0,q_0=0,</math>
+
== Локальность данных и вычислений ==
<math>2)</math> Считается норма вектора <math> b: \; \;  \|b\|_2 = \sqrt{\sum\limits_{j=1}^{n} b_j^2},</math>
 
<math>3)</math> Находится первый вектор матрицы <math> Q: \; \; q_{1} = \frac{b_{j}}{\|b\|_2},</math>
 
<math>4)</math> Начинается цикл, повторяющийся <math> k </math> раз по переменной <math> j: </math>
 
    <math>4.1)</math> Считается произведение матрицы на вектор: <math> z_d = \sum\limits_{y=1}^{n} a_{dy} q_{j_y}, \; d = 1,\,\dots\,, n, </math> где
 
    <math>z_d - </math> компоненты вектора Ланцоша <math>z, </math>
 
    <math>4.2)</math> Скалярно умножается <math>q_j^T</math>  и <math> z: \; \; \alpha_j = \sum\limits_{d=1}^{n}q_{j_d} z_d,</math>
 
    <math>4.3)</math> Вычисляется линейная комбинация векторов <math>z=z-\alpha_jq_j-\beta_{j-1}q_{j-1},  </math>
 
    <math>4.4)</math> <math>t</math> Присваивается <math>j - 1.  </math> В цикле по <math> i </math> от первого до посчитанного <math> t</math>-го собственного вектора проводится
 
    выборочная ортогонализация к сошедшимся векторам Ритца. То есть:
 
      <math>4.4.1)</math> Считается норма матрицы <math>\|T_{t}\|_2, </math> <math> \| T \|_2 =  \sup\limits_{\| x \|_2 = 1} \| T x \|_2 = \sup\limits_{(x, x) = 1} \sqrt{(Tx, Tx)}</math>, подчиненная векторной норме <math> \| x \|_2 = \sqrt{\sum_{i = 1}^n |x_i|^2} </math>. Т.е.
 
      <math> \|    T_{t} \|_2 =  \max\limits_{i=1 \dots t} \theta_i</math>, где <math> \theta_i</math> - собственные значения матрицы <math> T,</math>
 
      <math>4.4.2)</math> Берется <math>t</math>-ю координата вектора <math> v_i</math>  и проверяется, выполняется ли равенство:<math>\beta_{t}|v_i(t)| \leqslant \sqrt{\varepsilon}\|T_{t}\| \, \, ,</math>
 
      Если выполняется, то
 
          <math>4.4.2.1)</math> Ищется вектор Ритца <math>y_{i,t_d} = \sum\limits_{x=1}^{t} q_{x_d} v_{i_x}, \; d = 1,\,\dots\,, n,</math>, где  <math>y_{i,t_d}</math> -  <math>d</math>-я компонента вектора Ритца <math>y,</math>
 
          <math>4.4.2.2)</math> Скалярно умножается <math>y_{i,t}^T</math>  и <math> z: \; \; \gamma = \sum\limits_{d=1}^{n}y_{i,t_d} z_d,</math>
 
          <math>4.4.2.3)</math> Вычисляется линейная комбинация векторов <math>z = z-\gamma\,  y_{i,t}, </math>
 
          <math>4.4.2.4)</math> Увеличивается <math>i </math>. Производится возврат к пункту <math>4.4.2,</math>
 
    <math>4.5)</math> Ищется норма вектора <math> z: \; \; \beta_{j}=\|z\|_2, </math>
 
    <math>4.6)</math> Ищется вектор Ланцоша <math>q_{j+1}=z/\beta_{j}, </math>
 
    <math>4.7)</math> Вычисляется новое собственное значение <math> \theta_j </math> и собственный вектор <math> v_j </math> для полученной матрицы <math> T_j,</math>
 
    <math>4.8)</math> Увеличивается <math> j </math>, производится возврат к шагу <math>4.1.</math>
 
  
===Последовательная сложность алгоритма===
+
== Возможные способы и особенности параллельной реализации алгоритма ==
Рассмотрим последовательную сложность алгоритма.
 
<math>1)</math> Инициализируются векторы,
 
<math>2)</math> Считается норма вектора: <math> n </math> сложений и умножений, одно вычисление корня,
 
<math>3)</math> Находится первый вектор матрицы: <math> n </math> делений,
 
<math>4)</math> Начинается цикл, повторяющийся <math> k </math> раз по переменной : <math>  j </math>:
 
    <math>4.1)</math> Считается произведение матрицы на вектор: <math>  n </math> сложений и умножений,
 
    <math>4.2)</math> Скалярно умножается два вектора : <math>  n </math> сложений и умножений,
 
    <math>4.3)</math> Вычисляется линейная комбинация векторов : <math>  2n </math> вычитаний и умножений,
 
    <math>4.4)</math> Повторяется цикл : <math>  j-1 </math> раз. На каждом из этапов:
 
      <math>4.4.1)</math> Считается норма матрицы: : <math>  j-1 </math> сравнений,
 
      <math>4.4.2)</math> Проверяется равенство::  2 умножения, одно сравнение
 
          <math>4.4.2.1)</math> Ищется вектор Ритца : <math>  n*(j-1) </math> сложений и умножений,
 
          <math>4.4.2.2)</math> Скалярно умножаются два вектора:  <math>  n </math> сложений и умножений,
 
          <math>4.4.2.3)</math> Вычисляется линейная комбинация векторов : <math>  n </math> умножений и вычитаний,
 
          <math>4.4.2.4)</math> Увеличивается <math>i </math>. Одно сложение.
 
      Таким образом, т.к. внутренний цикл повторяется <math>  j-1 </math> раз, а <math>  j </math> в свою очередь пробегает от <math>1 \dots k </math>, значит, полное количество операций в пункте <math>4.4)</math>, которое будет занимать весь внутренний цикл будет: сравнений <math> \frac{(k-1)k(k+1)}{3} + \frac{k(k-1)}{2} </math>, умножений: <math> 2\frac{k(k-1)}{2}  + \frac{(k-1)k(k+1)}{3} + \frac{(2n)k(k-1)}{2} </math>, сложений <math>\frac{(k-1)k(k+1)}{3} + \frac{(n+1)k(k-1)}{2}</math> и вычитаний <math> \frac{(n)k(k-1)}{2}</math>
 
    <math>4.5)</math> Ищется норма вектора: <math> n </math> сложений и умножений
 
    <math>4.6)</math> Ищется вектор Ланцоша <math> n </math> делений
 
    <math>4.7)</math> Увеличивается <math> j </math>, одно сложение.
 
   
 
    Так, пункты  <math>4.1 - 4.3, 4.5 - 4.7</math> занимают <math> k*(n+n+n+1)</math> сложений, <math>k(n+n+2n+n)</math> умножений, <math>2nk</math> вычитаний и <math>n</math> делений.
 
 
 
 
Подводя итог, общее количество операций умножения и деления <math>n + n + 2\frac{k(k-1)}{2}  + \frac{(k-1)k(k+1)}{3} + \frac{(2n)k(k-1)}{2} +  k(n+n+2n+n) + n</math>, т.е. <math>O( k^3+nk^2+k^2+kn+n )</math>
 
общее количество сложений и вычитаний: <math> n + \frac{(k-1)k(k+1)}{3} + \frac{(n+1)k(k-1)}{2}+ \frac{(n)k(k-1)}{2} + k*(n+n+n+1) + 2nk</math>, т.е.  <math>O( k^3+nk^2+kn+n )</math>
 
И <math> \frac{(k-1)k(k+1)}{3} + \frac{k(k-1)}{2} </math> сравнений ( <math>O( k^3+k^2)</math>).
 
  
 +
== Масштабируемость алгоритма и его реализации ==
  
 +
Исследование масштабируемости алгоритма проводилось на суперкомпьютере
 +
[//hpc.cmc.msu.ru/ IBM Blue Gene/P ВМК МГУ.]
  
[[File:Graph.jpg|200px|right| frame |рис. 1: Информационный граф]]
+
Для тестирования была выбрана реализация
 +
[//crd-legacy.lbl.gov/~osni/marques.html#BLZPACK BLZPACK]. BLZPACK написан
 +
на FORTRAN 77 в 2001 году и использует MPI для параллелизма.
  
=== Информационный граф===
+
Для запуска BLZPACK необходима программа-драйвер. Использовался один из
На рисунке (рис. 1) изображен информационный граф. Ниже приведено его описание:
+
встроенных драйверов DRVMPI (файл <tt>drv/double/drvmpi.f</tt>) c измененными
 +
параметрами -- они меняются в зависимости от размера матрицы и количества
 +
требуемых пар собственных значений/векторов. Параметры устанавливаются в начале
 +
файла drvmpi.f.
  
* Вершины 1 соответствуют операции  <math>Aq_j,</math>.
+
Поскольку в мануале (<tt>doc/manual.ps</tt>) нету полного описания этих параметров,
* Вершины 2 соответствуют операции скалярного произведения <math>q_j^Tz</math>.
+
прокомментируем некоторые из них. Например, для матрицы размера 7500х7500
* Вершины 3 соответствуют операции <math>z-\sum\nolimits_{i=1}^{j-1}(z^Tq_i)q_i</math>.
+
использовались следующие значения:
* Вершины 4 соответствуют операции <math>z-\alpha_jq_j-\beta_{j-1}q_{j-1}</math>.
 
* Вершины 5 соответствуют операции <math>||z||</math>.
 
* Вершины 6 соответствуют операции <math>z/\beta_j</math>.
 
  
=== Ресурс параллелизма алгоритма===
+
<pre>
 +
      INTEGER          LEIG
 +
      PARAMETER        (LEIG  =     30)
  
Хотя алгоритм является итерационным, возможно распараллелить внутри каждой итерации умножение матрицы на вектор и процесс переортогонализации Грамма-Шмидта.
+
      INTEGER          LISTOR
 +
      PARAMETER        (LISTOR =  15000)
  
Процесс умножения матриц matvec можно распараллелить несколькими способами[https://eprint.iacr.org/2011/416.pdf].
+
      INTEGER          LN
 +
      PARAMETER        (LN    =    7500)
  
Как видно из графа, для выполнения j-й операции, необходимо выполнить следующие ярусы:
+
      INTEGER          LRSTOR
# <math>n</math> ярусов сложений с <math>n</math> операциями умножения в каждом (вычисление <math>z</math>);
+
      PARAMETER        (LRSTOR =  10000000)
# <math>n</math> ярусов сложений с <math>1</math> операцией умножения в каждом (вычисление <math>\alpha_j</math>);
 
# <math>j</math> ярусов сложений с <math>n</math> операциями умножения в каждом, <math>n</math> ярусов сложений с <math>j</math> операциями умножения в каждом, <math>1</math> ярус вычитаний размера <math>n</math> (первая переортогонализация);
 
# <math>j</math> ярусов сложений с <math>n</math> операциями умножения в каждом, <math>n</math> ярусов сложений с <math>j</math> операциями умножения в каждом, <math>1</math> ярус вычитаний размера <math>n</math> (вторая переортогонализация);
 
# <math>n</math> ярусов сложений с <math>1</math> операцией умножения в каждом (вычисление <math>\beta_j</math>);
 
# <math>1</math> ярус делений размера <math>n</math> (вычисление <math>q_{j + 1}</math>).
 
  
Если учесть весь ресурс параллелизма, можно получить мультипликативную вычислительную сложность всего алгоритма: <math>O(n^2k+nk^2)/p)</math>.
+
      INTEGER          NCUV
 +
      PARAMETER        (NCUV  =      1)
  
Вычислительная мощность данного алгоритма, как отношение числа операций к суммарному объему входных и выходных, данных равняется <math>O(k)</math>.
+
      INTEGER          NNZMAX
 +
      PARAMETER        (NNZMAX = 28128750)
  
=== Входные и выходные данные алгоритма===
+
      DOUBLE PRECISION ONE
'''Входные данные'''
+
      PARAMETER        (ONE    = 1.0D0)
  
Матрица <math> A </math>, начальный вектор  <math> b </math> и число собственных значений, которые мы хотим найти  <math> k </math>.
+
      DOUBLE PRECISION ZERO
 +
      PARAMETER        (ZERO  = 0.0D0)
 +
</pre>
  
Ввиду симметричности из матрицы <math> A </math> достаточно хранить только ее диагональ и элементы, лежащие выше ее. Таким образом, объем входных данных:
+
*<tt>LEIG</tt> -- размер массива для хранения полученных собственных
 +
векторов/значений.
 +
*<tt>LISTOR</tt> -- размер массива <tt>ISTOR</tt>. Формула определения его минимального размера приведена в мануале.
 +
*<tt>LN</tt> -- порядок матрицы <tt>A</tt>, т.е. <tt>n</tt>.
 +
*<tt>LRSTOR</tt> -- размер массива <tt>RSTOR</tt>. Формула определения его минимального размера приведена в мануале.
 +
*<tt>NNZMAX</tt> -- количество строк во входном файле с матрицей А. Драйвер <tt>DRVMPI</tt> прочитывает симметричную верхнетреугольную матрицу из файла в координатном формате (строка, столбец, значение); таким образом, для плотной матрицы <tt>NNZMAX</tt> будет равен <math>(n^2 + n)/2</math>
  
<math>\frac{n (n + 1)}{2} + n + 1 = \frac{n^2+3n+2}{2}.</math>
+
Сам запуск <tt>DRVMPI</tt> конфигурируется в файле <tt>drvsp1.dat</tt> -- там задаётся количество требуемых
 +
собственных значений/векторов, имя файла со входной матрицей и некоторые другие параметры.
  
'''Выходные данные'''
+
Входные матрицы генерировались следующим простым скриптом на Python 2.7:
  
Матрица собственных значений <math> \Lambda = diag(\theta_1 \dots \theta_k) </math>, матрица собственных векторов <math> V = [v_1 \dots v_k] </math> размера <math> n \times k </math>
+
<pre>
 +
import random
  
Так, объем выходных данных: <math> k + kn </math>
+
if __name__ == "__main__":
 +
    n = 7500
 +
    num_rows = (n*n + n) / 2
  
=== Свойства алгоритма ===
+
    with open('matr7500.data', 'w') as f:
Если <math>A</math> эрмитова матрица, то алгоритм Ланцоша и Bi-Lanczos сходятся к одинаковым трехдиагональным матрицам Ритца[http://ta.twi.tudelft.nl/nw/users/vuik/papers/DUT-TWI-96-44.pdf].
+
        for i in xrange(1, n + 1):
 +
            j = i  # column number
 +
            while j <= n:
 +
                value = random.uniform(-1, 1)
 +
                f.write("    " + str(i) + "    " + str(j) + "    " + '{:.14e}'.format(value) + "\n")
 +
                j += 1
  
При реализации классического алгоритма Ланцоша возникает большая погрешность при округлении. Вариант с полной переортогонализацией позволяет избегать больших погрешностей, однако является более ресурсоемким.  Вариант с частичной переортогонализацией является промежуточным.
+
</pre>
  
Алгоритм может завершить свою работу досрочно, когда найденные собственные значения будут достаточно близки к целевым.
+
Был использован компилятор GNU Fortran 77 (g77), точнее, его обертка
 +
<tt>mpif77</tt> с поддержкой MPI. На Blue Gene/P используется собственная
 +
реализация MPI от IBM, основанная на MPICH. Для сборки BLZPACK на Blue Gene/P
 +
нужно заменить имя компилятора (ключ FC) в файле <tt>sys/MACROS/Linux</tt> на
 +
<tt>mpif77</tt> и запустить <tt>./creator -f -mpi</tt> в корне проекта.  После
 +
этого можно собрать драйвер, зайдя в директорию <tt>drv/data</tt> и выполнив
 +
<tt>make drvmpi.x</tt>.
  
== Программная реализация алгоритма==
+
Использовался SMP-режим работы Blue Gene/P, когда на каждом вычислительном
=== Особенности реализации последовательного алгоритма===
+
узле выполняется всего один MPI-процесс.
=== Локальность данных и вычислений===
 
=== Возможные способы и особенности параллельной реализации алгоритма===
 
  
=== Масштабируемость алгоритма и его реализации ===
+
Пример запуска программы:
Исследование масштабируемости реализации алгоритма проводилось с использованием стандарта MPI на суперкомпьютере "Ломоносов".
+
<pre>
 +
mpisubmit.bg -n 64 -w 00:15:00 -m smp  --stdout eigen.out --stderr eigen.err drvmpi.x
 +
</pre>
  
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма:
+
Тестировались следующие конфигурации:
*Число процессоров 4, 8, 16, 32, 64, 128.
+
* Порядок матриц 1000, 2500, 5000, 7500
*Размерность матрицы от 1000 до 50000
+
* Количество процессоров 4, 8, 16, 32, 64, 128
Сборка осуществлялась с параметрами:
 
*openmpi/1.5.5-icc
 
*intel/13.1.0
 
  
[[File:time_dependance.jpg| center|border |800px]]
+
У матрицы размера 1000 производился поиск 100 пар собственных векторов/значений,
[http://pastebin.com/SbNrh7nz  Используемая параллельная реализация алгоритма на языке C++]
+
у остальных -- 30 пар. Результаты приведены в таблице 1:
  
На данном графике отчетливо видно, что время выполнения алгоритма сильно уменьшается с увеличением количества процессов при расчете матрицы любой размерности. При этом наблюдается некоторое снижение производительности в случае наибольших размеров матриц. Данный факт является следствием большого количества данных, необходимого для обмена между процессами. Отсюда опытным путем можно установить, что наибольшая производительность алгоритма будет достигнута, если размерность матрицы не будет превышать 30000-35000.
+
{| class="wikitable" style="border: none; background: none;"
 +
|+ align="bottom" style="caption-side: bottom" | Табл. 1. Результаты тестирования. В ячейках таблицы -- время работы алгоритма в секундах.
 +
! colspan="2" rowspan="2" style="border: none; background: none;"|[[File:Pfeil_SO.svg|none|20px]]
 +
! colspan="6"| Число процессоров
 +
|-
 +
! 4 !! 8 !! 16 !! 32 !! 64 !! 128
 +
|-
 +
! rowspan="4"| Размер матрицы
 +
! 1000
 +
| 24 || 17 || 14 || 15 || 16 || 21
 +
|-
 +
! 2500
 +
| 48 || 27 || 18 || 13 || 12 || 13
 +
|-
 +
! 5000
 +
| 207 || 92 || 61 || 37 || 24 || 23
 +
|-
 +
! 7500
 +
| 612 || 298 || 153 || 90 || 50 || 42
 +
|}
  
=== Динамические характеристики и эффективность реализации алгоритма===
+
Заметно, при всех размерах матриц алгоритм перестает масштабироваться начиная с
=== Выводы для классов архитектур===
+
некоторого числа процессоров: для матрицы размера 1000 это 32 узла, для матрицы
=== Существующие реализации алгоритма===
+
размера 2500 64 узла и т.д. Это связано с тем, что затраты на коммуникацию между
Алгоритм Ланцоша реализован в различных пакетах, библиотеках и проектах
+
узлами становится больше, чем выгода от распараллеливания вычислений. При
 +
меньшем же количестве процессоров алгоритм хорошо масштабируется, соответствуя
 +
теоретически вычисленной высоте ярусно-параллельной формы <math>O(kn + k^2)</math>
  
NAG Library http://www.nag.com/content/nag-library C, C++, Fortran, C#, MATLAB, R
+
== Динамические характеристики и эффективность реализации алгоритма ==
  
ARPACK https://people.sc.fsu.edu/~jburkardt/m_src/arpack/arpack.html MATLAB
+
== Выводы для классов архитектур ==
  
GrapLab https://turi.com/products/create/open_source.html C++
+
== Существующие реализации алгоритма ==
  
Gaussian Belief Propagation Matlab Package http://www.cs.cmu.edu/~bickson/gabp/ MATLAB
+
Неплохой обзор существующих реализаций находится здесь:
 +
[http://slepc.upv.es/documentation/reports/str6.pdf A Survey of Software for Sparse Eigenvalue Problems]
  
The IETL Project http://www.comp-phys.org/software/ietl/ C++
+
Ниже будут перечислены только те реализации, которые поддерживают именно выборочную ортогонализацию.
  
LANSO/PLANSO http://web.cs.ucdavis.edu/~bai/ET/lanczos_methods/overview_PLANSO.html Fortran
+
* [http://crd-legacy.lbl.gov/~osni/ BLZPACK] FORTRAN 77, MPI. 2000 год.
 +
* [http://www.cas.mcmaster.ca/~qiao/BLKLAN BLKLAN] C, MATLAB. Нет поддержки параллелизма. 2003 год.  
 +
* [http://sun.stanford.edu/~rmunk/PROPACK/ PROPACK] FORTRAN 77, MATLAB. OpenMP. Предназначен для нахождения SVD разложения, но алгоритм Ланцоша может быть вызван и напрямую. 2005 год.
 +
* [http://www.netlib.org/lanz/ LANZ] FORTRAN 77. Нет поддержки параллелизма. 1991 год.
 +
* [http://www.netlib.org/svdpack/ SVDPACK] C, FORTRAN 77. Нет поддержки параллелизма. Предназначен для нахождения SVD разложения. 1992 год.
  
Julia Math  https://github.com/JuliaMath/IterativeSolvers.jl Julia
+
= Литература =
  
==Литература ==
+
* Дж. Деммель, Вычислительная линейная алгебра. Теория и приложения. Пер. с англ. - М.: Мир, 2001.

Версия 11:51, 30 января 2017

Авторы: Абдулпотиев А.А. Шаблон:Временная статья

Авторы: Абдулпотиев А.А.



Алгоритм Ланцоша для арифметики с плавающей точкой с выборочной ортогонализацией
Последовательный алгоритм
Последовательная сложность [math]O(kn^2 + k^2n)[/math]
Объём входных данных [math]n^2 + n + 1[/math]
Объём выходных данных [math]nk[/math]
Параллельный алгоритм
Высота ярусно-параллельной формы [math]O(kn + k^2)[/math]
Ширина ярусно-параллельной формы [math]O(n)[/math]


1 Свойства и структура алгоритма

1.1 Общее описание алгоритма

Прежде чем приступить к описанию алгоритма, нужно немного рассказать о самой проблеме, которую решает алгоритм Ланцоша и понятия, которые необходимы для освоения дальнейшего материала. Кратко говоря алгоритм Ланцоша это итерационный метод нахождения небольшого количества собственных значений столь больших разреженных симметричных матриц, что к ним нельзя применить прямые методы. Иными словами алгоритм сильно оптимизирует использование памяти и вычислительной мощности, что является критически важным для больших вычислений.

Нам понадобятся сведения о крыловских подпронстранствах, симметричной проблеме собственных значений, а также о степенном методе и обратной итерации.

Сам алгоритм объединяет метод Ланцоша для построения крыловского подпространства с процедурой Рэлея-Ритца интерпретации собственных значений некоторой вычисляемой матрицы как приближений к собственным значениям исходной матрицы.

Пусть [math]Q = [Q_k,Q_u][/math] - ортогональная матрица порядка [math]n[/math], причем [math]Q_k[/math] и [math]Q_u[/math] имеют соответственно размеры [math]n \times k[/math] и [math]n \times (n-k)[/math]. Столбцы матрицы [math]Q_k[/math] вычисляются методом Ланцоша..

Запишем следующие соотношения:

[math]T = Q^T A Q = [Q_k, Q_u]^T A [Q_k, Q_u] = \left[ \begin{array}{cc} Q_k^T A Q_k & Q_k^T A Q_u\\ Q_u^T A Q_k & Q_u^T A Q_u \end{array} \right] = \left[ \begin{array}{cc} T_{k} & T_{ku}^T\\ T_{ku} & T_{u} \end{array} \right][/math]

Метод Рэлея-Ритца заключается в интерпретации собственных значений матрицы [math]T_k = Q_k^T A Q_k[/math] как приближенных к собственным значениям матрицы [math]A[/math]. Эти приближения называются числами Ритца. Если [math]A = V \Lambda V^T[/math] есть спектральное разложение матрицы [math]T_k[/math], то столбцы матрицы [math]Q_k V[/math] являются приближениями соответствующих собственных векторов и называются векторами Ритца.

Числа и векторы Ритца являются оптимальными приближениями к собственным значениям и собственным векторам матрицы [math]A[/math].

При применении метода Ланцоша в арифметике с плавающей точкой ортогональность в вычисленных векторах Ланцоша [math]q_k[/math] пропадает из-за ошибок округления. Потеря ортогональности не заставляет алгоритм вести себя совершенно не предсказуемым образом. В самом деле, мы увидим, что цена, которую мы платим за потерю, это приобретение повторных копий сошедшихся чисел Ритца. Для того чтобы поддержать взаимную ортогональность векторов Ланцоша, существуют две модификации алгоритма.

  1. Алгоритм Ланцоша с полной переортогонализацией. На каждой итерации запускается повторный процесс ортогонализации Грамма-Шмидта [math]z = z - \textstyle \sum_{i=1}^{j-1} (z^T q_i)q_i \displaystyle[/math]
  2. Алгоритм Ланцоша с выборочной ортогонализацией. Согласно теореме Пейджа векторы [math]q_k[/math] теряют ортогональность весьма систематическим образом, а именно, приобретая большие компоненты в направлениях уже сошедшихся векторов Ритца (Именно это приводит к появлению повторных копий сошедшихся чисел Ритца). Поэтому можно выборочно ортогонализировать векторы [math]q_k[/math] вместо того, чтобы на каждом шаге ортогонализировать вектор ко всем ранее сошедшимся векторам, как это делается при полной ортогонализации. Таким образом достигается (почти) ортогональности векторов Ланцоша, затрачивая очень небольшая дополнительную работу.

1.2 Математическое описание алгоритма

Пусть [math]A[/math] - заданная симметричная матрица, [math]b[/math] - вектор начального приближения метода Ланцоша. Тогда алгоритм Ланцоша вычисления собственных векторов и собственных значений матрицы [math]A[/math] с выборочной ортогонализацией имеет следующий вид:

[math] \begin{align} q_1 = & b / \Vert b \Vert_2, \; \beta_0 = 0,\; q_0 = 0\\ for \; & j = 1 \; to \; k \\ & z = A\,q_j\\ & \alpha_j = q_j^T z\\ & z = z - \alpha_j q_j - \beta_{j-1}q_{j-1}\\ & t = j-1\\ & for \; i=1 \; to \; t \\ & \; \; \; if \; \beta_t \|v_i (t)\| \le \sqrt{\epsilon} \Vert T_t \Vert_2 \; then\\ & \; \; \; \; \; \; z = z - (y_{i,t} ^ T z) y_{i,t} \;/*\; y_{i,t} = Q_t v_i \;*/ \\ & end \; for\\ & \beta_j = \Vert z \Vert_2\\ & if \; \beta_j = 0 \; then\\ & \; \; \; Stop\; the\; algorithm\\ & q_{j+1} = z / \beta_j\\ & /*Calculate\; eigenvalues\; and\; eigenvektors\; of\; T_j\; */\\ end \; & for \end{align} [/math]

Где [math]v_i[/math] - это столбцы ортогональной матрицы [math]V[/math] из спектрального разложения [math]T_t = V \Lambda V^T[/math], а [math]y_{t,i} = Q_t v_i[/math] - столбцы матрицы [math]Q_t V[/math] - векторы Ритца.

Согласно теореме Пейджа, [math]y_{t,i}^T q_{t+1} = O(\epsilon \Vert A \Vert_2) / \beta_t \Vert v_i(t) \Vert[/math], то есть компонента [math]y_{t,i}^T q_{t+1}[/math] вычисленного вектора Ланцоша [math]q_{t+1}[/math] в направлении вектора Ритца [math]y_{t,i} = Q_t v_i[/math] обратно пропорциональна величине [math]\beta_t \Vert v_i(t) \Vert[/math], являющейся оценкой погрешности для соответствующего числа Ритца. Поэтому, когда число Ритца сходится, а его оценка погрешности приближается к нулю, вектор Ланцоша приобретает большую компоненту в направлении вектора Ритца [math]q_{t,i}[/math], и следует произвести процедуру переортогонализации.

Величина погрешности [math]\beta_t \Vert v_i(t) \Vert[/math] считается малой, если она меньше, чем [math]\sqrt{\epsilon} \Vert A \Vert_2[/math], так как в этом случае, согласно теореме Пейджа, компонента [math]\Vert y_{i,t}^T q_{t+1} \Vert = \Vert y_{i,t}^T z \Vert / \Vert z \Vert_2[/math] скорее всего превосходит уровень [math]\sqrt{\epsilon}[/math] (на практике используется [math]\Vert T_t \Vert_2[/math] вместо [math]\Vert A \Vert_2[/math], так как первое известно, а второе не всегда).

1.3 Вычислительное ядро алгоритма

У описанного алгоритма два ядра, на которые приходится основное время работы алгоритма:

  • Вычисление вектора [math]z = A q_j: O (n^2)[/math] операций умножения.
  • Выборочная переортогонализация [math]z = z - (y_{i,t} ^ T z) y_{i,t}[/math], где [math]i = 1\dots t[/math].

1.4 Макроструктура алгоритма

Макроструктура алгоритма Ланцоша с выборочной переортогонализацией представляется в виде совокупности метода Ланцоша с выборочной переортогонализацией построения крыловского подпространства и процедуры Рэлея-Ритца.

Каждая итерация первого этапа может быть разложена на следующие макроединицы:

  • Умножение матрицы на вектор
  • Вычисление скалярного произведения векторов
  • Умножение векторов на числа и вычитание векторов
  • При выполнении условия необходимости переортогонализации – перемножение и вычитание векторов
  • Вычисление нормы вектора
  • Умножение вектора на число

Второй этап, процедура Рэлея-Ритца, заключается в нахождении собственных значений и собственных векторов матрицы и интерпретации их как приближенных значений собственных чисел и собственных векторов исходной матрицы, он может быть выполнен любым способом, например, QR-итерацией.

1.5 Схема реализации последовательного алгоритма

На вход алгоритму подаются исходная матрица [math]A[/math], вектор начального приближения [math]b[/math] и число [math]k[/math]. Далее последовательно выполняются итерационно для всех [math]j: 1 \le j \le k[/math] следующие шаги:

  1. Умножается матрица на вектор для нахождения вектора [math]z[/math]
  2. Вычисляется коэффициент [math]\Alpha_j[/math] посредством скалярного перемножения векторов
  3. Вычисляется новое значение вектора [math]z[/math]
  4. Производятся оценка погрешностей [math]\beta_t \Vert v_i(t) \Vert[/math], где [math]t = j - 1[/math] и выборочная переортогонализация
  5. Вычисление очередного значения [math]\beta_j[/math] - норма вектора [math]z[/math]
  6. Вычисление и добавление к матрице [math]Q[/math] нового столбца
  7. Вычисление собственных значений и собственных векторов матрицы [math]T_j[/math]

1.6 Последовательная сложность алгоритма

  • Вычисление вектора [math]z[/math] - [math]n^2[/math] операций умножения и [math]n(n-1)[/math] операций сложения
  • Вычисление скалярного произведения векторов - [math]n[/math] операций умножения и [math](n-1)[/math] сложений
  • Вычисление вектора [math]z[/math] - [math]2n[/math] умножений и [math]2n[/math] сложений
  • Оценка погрешностей - [math]kn[/math] операций умножения
  • Выборочная переортогонализация - [math]O(2nj)[/math] умножений и [math]O(2j(n-1) + n)[/math] сложений
  • Вычисление нормы вектора - [math]n[/math] операций умножения и [math](n-1)[/math] сложений
  • Вычисление нового столбца матрицы [math]Q[/math] - [math]n[/math] операций умножения

Итого на каждой итерации:

  • Умножений: [math]n^2 + n + 2n + kn + O(2nj) + n + n = n^2 + 5n + kn + O(2nj)[/math]
  • Сложений: [math]n(n-1) + n-1 + 2n + O(2j(n-1) + n) + n-1 = n^2 + 3n + O(2j(n-1) + n) -2[/math]

Итого за все время выполнения алгоритма:

  • Умножений: [math]kn^2 + 5kn + k^2n + O(k^2n + kn)[/math]
  • Сложений: [math]kn^2 + 3kn + O((k^2+k)(n-1)+kn) = kn^2 + 3kn + O(k^2(n-1)+2kn-k)[/math]

Суммарная последовательная сложность алгоритма - [math]O(kn^2 + k^2n)[/math].

1.7 Информационный граф

Ниже представлен граф одной итерации алгоритма с разделением на [math]n[/math] потоков.

Рисунок 1. Детальный граф алгоритма Ланцоша с выборочной переортогонализацией.

Oper - простая операция сложения/вычитания/умножения/деления с числами с плавающей точкой.
'?' - проверка условия на необходимость переортогонализации.

На вход итерации подается матрица [math]A[/math] и вектор [math]q_j[/math], на выходе получаем новый вектор [math]q_{j+1}[/math].


1.8 Ресурс параллелизма алгоритма

На каждой из итераций алгоритма можно получить выигрыш за счет распараллеливания следующих шагов:

  • Вычисление вектора [math]z[/math] - умножение матрицы размера [math]n \times n[/math] на вектор длины [math]n[/math] - [math]n[/math] ярусов сложений, [math]n[/math] операций умножений в каждом
  • Вычисление коэффициента [math]\alpha_j[/math] - скалярное произведение векторов - [math]n[/math] ярусов сложений, 1 операция умножения в каждом
  • Вычисление нового значения вектора [math]z[/math]: 2 яруса умножений длины [math]n[/math] (умножение вектора на число), 2 яруса вычитаний длины [math]n[/math]
  • Выборочная переортогонализация: последовательно для всех [math]i \le k[/math] выполняется [math]j[/math] ярусов сложений, [math]n[/math] операций умножений в каждом, [math]n[/math] ярусов сложений, [math]j[/math] операций умножений в каждом, один ярус вычитаний размера [math]n[/math]
  • Вычисление [math]\beta_j[/math] - скалярное произведение векторов - [math]n[/math] ярусов сложений, 1 операция умножения в каждом
  • Вычисление [math]q_j[/math] - деление вектора на число - один ярус делений размера [math]n[/math]

Сложность алгоритма по ширине ЯПФ - [math]O(n)[/math].

1.9 Входные и выходные данные алгоритма

Входные данные: вещественная матрица [math]A[/math] размера [math]n \times n[/math], вектор [math]b[/math] длины [math]n[/math], число [math]k[/math]

Объем входных данных: [math]n^2 + n + 1[/math]

Выходные данные: матрица [math]Q[/math] размера [math]n \times k[/math]

Объем выходных данных: [math]nk[/math]

1.10 Свойства алгоритма

  • Соотношение последовательной и параллельной сложности алгоритма равно [math]n[/math], что говорит о том, что параллельная реализация теоретически должна давать ощутимый выигрыш
  • Вычислительная мощность алгоритма - отношение числа операций к суммарному объему входных и выходных данных - примерно равно [math]2k[/math]
  • Алгоритм устойчив, так как операция переортогонализации как раз направлена на исключение проблемы округления вычисляемых значений
  • Алгоритм не является детерминированным, так как, во-первых, используется для разряженных матриц, и, во-вторых, является итерационным с выходом по точности - число операций заранее не определено
  • Алгоритм содержит длинные дуги, так как на протяжении всего процесса его выполнения нужно хранить исходную матрицу [math]A[/math] и матрицу [math]Q[/math] - они нужны на каждой итерации

2 Программная реализация алгоритма

2.1 Особенности реализации последовательного алгоритма

2.2 Локальность данных и вычислений

2.3 Возможные способы и особенности параллельной реализации алгоритма

2.4 Масштабируемость алгоритма и его реализации

Исследование масштабируемости алгоритма проводилось на суперкомпьютере IBM Blue Gene/P ВМК МГУ.

Для тестирования была выбрана реализация BLZPACK. BLZPACK написан на FORTRAN 77 в 2001 году и использует MPI для параллелизма.

Для запуска BLZPACK необходима программа-драйвер. Использовался один из встроенных драйверов DRVMPI (файл drv/double/drvmpi.f) c измененными параметрами -- они меняются в зависимости от размера матрицы и количества требуемых пар собственных значений/векторов. Параметры устанавливаются в начале файла drvmpi.f.

Поскольку в мануале (doc/manual.ps) нету полного описания этих параметров, прокомментируем некоторые из них. Например, для матрицы размера 7500х7500 использовались следующие значения:

      INTEGER          LEIG
      PARAMETER        (LEIG   =     30)

      INTEGER          LISTOR
      PARAMETER        (LISTOR =  15000)

      INTEGER          LN
      PARAMETER        (LN     =    7500)

      INTEGER          LRSTOR
      PARAMETER        (LRSTOR =  10000000)

      INTEGER          NCUV
      PARAMETER        (NCUV   =      1)

      INTEGER          NNZMAX
      PARAMETER        (NNZMAX =  28128750)

      DOUBLE PRECISION ONE
      PARAMETER        (ONE    =  1.0D0)

      DOUBLE PRECISION ZERO
      PARAMETER        (ZERO   =  0.0D0)
  • LEIG -- размер массива для хранения полученных собственных

векторов/значений.

  • LISTOR -- размер массива ISTOR. Формула определения его минимального размера приведена в мануале.
  • LN -- порядок матрицы A, т.е. n.
  • LRSTOR -- размер массива RSTOR. Формула определения его минимального размера приведена в мануале.
  • NNZMAX -- количество строк во входном файле с матрицей А. Драйвер DRVMPI прочитывает симметричную верхнетреугольную матрицу из файла в координатном формате (строка, столбец, значение); таким образом, для плотной матрицы NNZMAX будет равен [math](n^2 + n)/2[/math]

Сам запуск DRVMPI конфигурируется в файле drvsp1.dat -- там задаётся количество требуемых собственных значений/векторов, имя файла со входной матрицей и некоторые другие параметры.

Входные матрицы генерировались следующим простым скриптом на Python 2.7:

import random

if __name__ == "__main__":
    n = 7500
    num_rows = (n*n + n) / 2

    with open('matr7500.data', 'w') as f:
        for i in xrange(1, n + 1):
            j = i  # column number
            while j <= n:
                value = random.uniform(-1, 1)
                f.write("    " + str(i) + "    " + str(j) + "    " + '{:.14e}'.format(value) + "\n")
                j += 1

Был использован компилятор GNU Fortran 77 (g77), точнее, его обертка mpif77 с поддержкой MPI. На Blue Gene/P используется собственная реализация MPI от IBM, основанная на MPICH. Для сборки BLZPACK на Blue Gene/P нужно заменить имя компилятора (ключ FC) в файле sys/MACROS/Linux на mpif77 и запустить ./creator -f -mpi в корне проекта. После этого можно собрать драйвер, зайдя в директорию drv/data и выполнив make drvmpi.x.

Использовался SMP-режим работы Blue Gene/P, когда на каждом вычислительном узле выполняется всего один MPI-процесс.

Пример запуска программы:

mpisubmit.bg -n 64 -w 00:15:00 -m smp  --stdout eigen.out --stderr eigen.err drvmpi.x

Тестировались следующие конфигурации:

  • Порядок матриц 1000, 2500, 5000, 7500
  • Количество процессоров 4, 8, 16, 32, 64, 128

У матрицы размера 1000 производился поиск 100 пар собственных векторов/значений, у остальных -- 30 пар. Результаты приведены в таблице 1:

Табл. 1. Результаты тестирования. В ячейках таблицы -- время работы алгоритма в секундах.
Pfeil SO.svg
Число процессоров
4 8 16 32 64 128
Размер матрицы 1000 24 17 14 15 16 21
2500 48 27 18 13 12 13
5000 207 92 61 37 24 23
7500 612 298 153 90 50 42

Заметно, при всех размерах матриц алгоритм перестает масштабироваться начиная с некоторого числа процессоров: для матрицы размера 1000 это 32 узла, для матрицы размера 2500 64 узла и т.д. Это связано с тем, что затраты на коммуникацию между узлами становится больше, чем выгода от распараллеливания вычислений. При меньшем же количестве процессоров алгоритм хорошо масштабируется, соответствуя теоретически вычисленной высоте ярусно-параллельной формы [math]O(kn + k^2)[/math]

2.5 Динамические характеристики и эффективность реализации алгоритма

2.6 Выводы для классов архитектур

2.7 Существующие реализации алгоритма

Неплохой обзор существующих реализаций находится здесь: A Survey of Software for Sparse Eigenvalue Problems

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

  • BLZPACK FORTRAN 77, MPI. 2000 год.
  • BLKLAN C, MATLAB. Нет поддержки параллелизма. 2003 год.
  • PROPACK FORTRAN 77, MATLAB. OpenMP. Предназначен для нахождения SVD разложения, но алгоритм Ланцоша может быть вызван и напрямую. 2005 год.
  • LANZ FORTRAN 77. Нет поддержки параллелизма. 1991 год.
  • SVDPACK C, FORTRAN 77. Нет поддержки параллелизма. Предназначен для нахождения SVD разложения. 1992 год.

3 Литература

  • Дж. Деммель, Вычислительная линейная алгебра. Теория и приложения. Пер. с англ. - М.: Мир, 2001.