Участник:AleksLevin/Алгоритм Ланцоша вычисления собственных значений симметричной матрицы для точной арифметики (без переортогонализации): различия между версиями
ASA (обсуждение | вклад) |
|||
(не показано 145 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
− | Основные авторы описания: Левин А.Д. ( | + | {{Assignment|ASA|Konshin}} |
+ | |||
+ | Основные авторы описания: Левин А.Д. | ||
+ | |||
+ | |||
+ | {{algorithm | ||
+ | | name = Алгоритм Ланцоша для точной арифметики (без переортогонализации) | ||
+ | | serial_complexity = <math>O(k\,n^2)</math> | ||
+ | | pf_height = <math>O(k\log_2 n)</math> | ||
+ | | pf_width = <math>O(n^2)</math> | ||
+ | | input_data = <math>\frac{n^2+3n}{2} + 1</math> | ||
+ | | output_data = <math>k\;(n + 1)</math> | ||
+ | }} | ||
= Свойства и структура алгоритмов = | = Свойства и структура алгоритмов = | ||
Строка 7: | Строка 19: | ||
Данный алгоритм появился в 1950 г. и носит имя венгерского физика и математика Корнелия Ланцоша (венг. Lánczos Kornél). Алгоритм Ланцоша относится к итерационным методам вычисления собственных значений для матриц столь больших порядков <math style="vertical-align:0%;> n</math>, что к ним нельзя применить прямые методы из-за ограничений по времени и памяти. | Данный алгоритм появился в 1950 г. и носит имя венгерского физика и математика Корнелия Ланцоша (венг. Lánczos Kornél). Алгоритм Ланцоша относится к итерационным методам вычисления собственных значений для матриц столь больших порядков <math style="vertical-align:0%;> n</math>, что к ним нельзя применить прямые методы из-за ограничений по времени и памяти. | ||
− | Сам Ланцош указывал, что его метод предназначен для отыскания нескольких собственных векторов симметричных матриц, хотя к методу сразу было обращено внимание, как к способу приведения всей матрицы к трёхдиагональному виду. Двадцатью годами позже канадский математик Крис Пэж показал, что, несмотря на чувствительность к округлениям, алгоритм Ланцоша - эффективное средство вычисления некоторых <math style="vertical-align:0%;>k</math> собственных чисел и соответствующих им собственных векторов < | + | Сам Ланцош указывал, что его метод предназначен для отыскания нескольких собственных векторов симметричных матриц, хотя к методу сразу было обращено внимание, как к способу приведения всей матрицы к трёхдиагональному виду. Двадцатью годами позже канадский математик Крис Пэж показал, что, несмотря на чувствительность к округлениям, алгоритм Ланцоша - эффективное средство вычисления некоторых <math style="vertical-align:0%;>k</math> собственных чисел и соответствующих им собственных векторов. <ref>Парлетт Б. - Симметричная проблема собственных значений. Численные методы //М.: Мир. - 1983. (c. 276)</ref> |
− | Обычно число <math style="vertical-align:0%;>k</math> берут в два раза больше, чем количество собственных значений матрицы, которые поставлена цель найти, и оно имеет порядок не более <math style="vertical-align:-10%;>10^2</math><ref>Susan W. Bostic - Lanczos Eigensolution Method for High-Perfomance Computers, page 7</ref> | + | Обычно число <math style="vertical-align:0%;>k</math> берут в два раза больше, чем количество собственных значений матрицы, которые поставлена цель найти, и оно имеет порядок не более <math style="vertical-align:-10%;>10^2</math>.<ref>Susan W. Bostic - Lanczos Eigensolution Method for High-Perfomance Computers, page 7</ref> |
− | Алгоритм Ланцоша для вычисления собственных значений симметричной матрицы <math style="vertical-align:0%;>A</math> соединяет в себе метод Ланцоша для построения последовательности подпространств Крылова и ортонормированных векторов Ланцоша и процедуру Рэлея-Ритца получения оптимальных приближений собственных значений и соответствующих собственных векторов исходной матрицы <math style="vertical-align:0%;>A</math> < | + | Алгоритм Ланцоша для вычисления собственных значений симметричной матрицы <math style="vertical-align:0%;>A</math> соединяет в себе метод Ланцоша для построения последовательности подпространств Крылова и ортонормированных векторов Ланцоша и процедуру Рэлея-Ритца получения оптимальных приближений собственных значений и соответствующих собственных векторов исходной матрицы <math style="vertical-align:0%;>A</math>.<ref>James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 381)</ref> |
В данной статье рассматривается вариант алгоритма Ланцоша, в котором опущено влияние ошибок округления на вычислительный процесс, хотя на практике этому посвящается отдельное внимание и существуют различные методы решения данной проблемы, такие как частичная или полная переортогонализация. Этим модифицированным методам посвящены отдельные статьи на данном ресурсе. | В данной статье рассматривается вариант алгоритма Ланцоша, в котором опущено влияние ошибок округления на вычислительный процесс, хотя на практике этому посвящается отдельное внимание и существуют различные методы решения данной проблемы, такие как частичная или полная переортогонализация. Этим модифицированным методам посвящены отдельные статьи на данном ресурсе. | ||
== Математическое описание алгоритма == | == Математическое описание алгоритма == | ||
− | + | Обозначения и формулы, используемые в данном разделе, взяты из литературы, указанной по ссылке.<ref>James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 313, ''<math> \S </math> 6.6 Методы Крыловского подпространства'')</ref> | |
− | |||
− | Алгоритм Ланцоша для вычисления <math style="vertical-align:0%;>k</math> собственных значений и собственных векторов вещественной симметричной матрицы <math style="vertical-align:0%;>A=A^T</math> в точной арифметике < | + | Алгоритм Ланцоша для вычисления <math style="vertical-align:0%;>k</math> собственных значений и собственных векторов вещественной симметричной матрицы <math style="vertical-align:0%;>A=A^T</math> в точной арифметике: <ref>James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 381)</ref> |
<math> | <math> | ||
\begin{align} | \begin{align} | ||
q_1 = & \,\frac{b}{\|b\|_2},\; \beta_0 = 0,\; q_0 = 0\\ | q_1 = & \,\frac{b}{\|b\|_2},\; \beta_0 = 0,\; q_0 = 0\\ | ||
− | for \; & j = 1 \; to \; k \\ | + | \mathbf{for} \; & j = 1 \; to \; k \,\; \mathbf{do} \\ |
& z = A\,q_j\\ | & z = A\,q_j\\ | ||
& \alpha_j = q^T_j z\\ | & \alpha_j = q^T_j z\\ | ||
& z = z - \alpha_j q_j - \beta_{j-1}q_{j-1}\\ | & z = z - \alpha_j q_j - \beta_{j-1}q_{j-1}\\ | ||
& \beta_j = \|z\|_2\\ | & \beta_j = \|z\|_2\\ | ||
− | & If \; (\beta_j == 0) \; then\; stop\; the\; algorithm \\ | + | & \mathbf{If} \; (\beta_j == 0) \; \mathbf{then}\; stop\; the\; algorithm \\ |
& \; q_{j+1} = \frac{z}{\beta_j} \\ | & \; q_{j+1} = \frac{z}{\beta_j} \\ | ||
& compute\; eigenvalues\; and \;eigenvectors\;of \;matrix \;\;T_j= Q^T_j A Q\;\;and\;estimate \;the\; errors\\ | & compute\; eigenvalues\; and \;eigenvectors\;of \;matrix \;\;T_j= Q^T_j A Q\;\;and\;estimate \;the\; errors\\ | ||
− | end \; & for | + | \mathbf{end} \; & \mathbf{for} |
\end{align} | \end{align} | ||
</math> | </math> | ||
Строка 39: | Строка 50: | ||
Введём матрицу Крылова, определяемую следующим соотношением: <math>K_j = [b,Ab,A^2b,...,A^{j-1}b]</math>. | Введём матрицу Крылова, определяемую следующим соотношением: <math>K_j = [b,Ab,A^2b,...,A^{j-1}b]</math>. | ||
− | Далее, на практике, матрица <math style="vertical-align:0%;>K</math> заменяется матрицей <math style="vertical-align:-20%;>Q</math>, такой, что при любом числе <math style="vertical-align:0%;>k</math> линейные оболочки первых <math style="vertical-align:0%;>k</math> столбцов в <math style="vertical-align:0%;>K</math> и <math style="vertical-align:-20%;>Q</math> являются одним и тем же подпространством < | + | Далее, на практике, матрица <math style="vertical-align:0%;>K</math> заменяется матрицей <math style="vertical-align:-20%;>Q</math>, такой, что при любом числе <math style="vertical-align:0%;>k</math> линейные оболочки первых <math style="vertical-align:0%;>k</math> столбцов в <math style="vertical-align:0%;>K</math> и <math style="vertical-align:-20%;>Q</math> являются одним и тем же подпространством.<ref>James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 315)</ref> |
Тогда матрица <math style="vertical-align:-20%;>Q</math>, в отличие от матрицы <math style="vertical-align:0%;>K</math>, хорошо обусловлена и легко обратима. В результате получаем матрицу <math>Q_j = [q_1, q_2, \dots, q_j]</math> размерности <math>n\times j</math>, столбцы которой ортогональны, являются базисом подпространства Крылова и называются векторами Ланцоша. | Тогда матрица <math style="vertical-align:-20%;>Q</math>, в отличие от матрицы <math style="vertical-align:0%;>K</math>, хорошо обусловлена и легко обратима. В результате получаем матрицу <math>Q_j = [q_1, q_2, \dots, q_j]</math> размерности <math>n\times j</math>, столбцы которой ортогональны, являются базисом подпространства Крылова и называются векторами Ланцоша. | ||
В алгоритме Ланцоша вычислению подлежит столько первых столбцов в матрице <math style="vertical-align:-20%;>Q_j</math>, сколько необходимо для получения требуемого приближения к решению <math>A\,x\,=b\,\,(A\,x=\lambda \, x)</math>. | В алгоритме Ланцоша вычислению подлежит столько первых столбцов в матрице <math style="vertical-align:-20%;>Q_j</math>, сколько необходимо для получения требуемого приближения к решению <math>A\,x\,=b\,\,(A\,x=\lambda \, x)</math>. | ||
− | Получение нулевого <math>\beta_j</math> в итерационном процессе - событие, желательное в том смысле, что оно свидетельствует о том, что найдено некоторое подпространство, являющееся в точности инвариантным, а все собственные значения матрицы <math style="vertical-align:-20%;>T_j</math> являются собственными значениями матрицы <math style="vertical-align:0%;>A</math>. На практике же нулевое и близкие к нулю значения получаются редко < | + | Получение нулевого <math>\beta_j</math> в итерационном процессе - событие, желательное в том смысле, что оно свидетельствует о том, что найдено некоторое подпространство, являющееся в точности инвариантным, а все собственные значения матрицы <math style="vertical-align:-20%;>T_j</math> являются собственными значениями матрицы <math style="vertical-align:0%;>A</math>. На практике же нулевое и близкие к нулю значения получаются редко.<ref>Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 429)</ref> |
− | Затем на каждом шаге цикла формируется симметричная трёхдиагональная матрица <math>T_j = Q^T_j A Q</math>, к которой применяется процесс Рэлея-Ритца для поиска её собственных значений (на практике для поиска этих собственных значений можно использовать любой из специальных методов | + | Затем на каждом шаге цикла формируется симметричная трёхдиагональная матрица <math>T_j = Q^T_j A Q</math>, к которой применяется процесс Рэлея-Ритца для поиска её собственных значений (на практике для поиска этих собственных значений можно использовать любой из специальных методов в параграфе книги по ссылке).<ref>Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (<math>\S</math> 8.4)</ref> |
Эти собственные значения, они же числа Ритца, и полагаются приближёнными собственными значениями исходной матрицы <math style="vertical-align:0%;>A</math>. | Эти собственные значения, они же числа Ритца, и полагаются приближёнными собственными значениями исходной матрицы <math style="vertical-align:0%;>A</math>. | ||
− | + | <br> | |
+ | Существует множество методов для отыскания собственных значений вещественной симметричной трехдиагональной матрицы. Большинство из них требует <math>O(n^2)</math> операций <ref>Парлетт Б. Симметричная проблема собственных значений. Численные методы.,: Мир, 1983. с. 179-182</ref>, но существуют и быстрые алгоритмы, требующие лишь <math>O(n\ln n)</math> операций.<ref>https://en.wikipedia.org/wiki/Tridiagonal_matrix#Eigenvalues Раздел eigenvalues</ref> | ||
+ | <br><br> | ||
+ | Одним из возможных способов отыскать собственные значения симметричной трехдиагональной матрицы - прямое вычисление корней характеристического полинома <math>p_n(\lambda)</math> через метод деления пополам, где формируется последовательность Штурма и локализуются собственные числа, являющиеся корнями характеристического полинома. Нахождение всех <math>n</math> собственных значений матрицы этим способом требует <math style="vertical-align:0%;>2n^2t</math> умножений и вычитаний, где <math>t</math> - число сделанных шагов с применением метода деления пополам.<ref>Уилкинсон Дж. X. Алгебраическая проблема собственныx значений. Изд-во "Наука", 1970. - глава 5, с. 272-278</ref> Соответствующие собственные вектора могут быть найдены посредством обратных итераций за <math> O(n) </math> флопов. <ref>Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 394-395)</ref> <br> | ||
+ | <br>На практике, если требуется только небольшая часть от всей совокупности собственных векторов и значений, и матрица имеет Хессенбергову или трёхдиагональную форму, очень эффективными будут методы факторизации, как, например, QR-алгоритм или QL-алгоритм со сдвигами (c целью ускорить алгоритм и сделать порядок сходимости квадратичным) или же без них.<ref>http://algorithm.narod.ru/ln/eigen/ETridiag.html</ref> <br> | ||
+ | Весьма молодые и не менее актуальные конкуренты QR и QL алгоритмов, применяющиеся для поиска собственных значений: | ||
+ | *Методы divide-and-conquer (разделяй и властвуй), появившиеся в 1980-ых годах <ref>https://goo.gl/dapvbn ссылку пришлось сократить с помощью Google url shortener, так как символы подчеркивания портили её и не давали перейти по 1 клику</ref> | ||
+ | *Relatively robust representation методы, появившиеся в 1990-ых и позволяющие найти собственные числа симметричной матрицы порядка <math style="vertical-align:0%;>n</math> за <math>O(n^2)</math> операций | ||
Если требуется вычислить собственные векторы, то необходимо хранить вычисляемые векторы Ланцоша. Если работа при этом производится только с оперативной памятью, то при большом порядке исходной матрицы (а именно для таких матриц и предназначен метод Ланцоша) число шагов <math style="vertical-align:-10%;>j</math>, которые могут быть выполнены до того момента, как оперативная память будет исчерпана, будет очень незначительно, а следовательно, искомые собственные пары могут не успеть сойтись с требуемой точностью. В этом случае метод Ланцоша можно использовать итерационным образом: после выполнения заданного числа шагов процесс прерывается и, если еще не все требуемые пары Ритца сошлись с требуемой точностью, то формируется новый начальный вектор <math style="vertical-align:-20%;>q_1</math>, являющийся линейной комбинацией векторов Ритца, еще не сошедшихся с заданной точностью, и процесс начинается заново.<ref>http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.5)</ref> | Если требуется вычислить собственные векторы, то необходимо хранить вычисляемые векторы Ланцоша. Если работа при этом производится только с оперативной памятью, то при большом порядке исходной матрицы (а именно для таких матриц и предназначен метод Ланцоша) число шагов <math style="vertical-align:-10%;>j</math>, которые могут быть выполнены до того момента, как оперативная память будет исчерпана, будет очень незначительно, а следовательно, искомые собственные пары могут не успеть сойтись с требуемой точностью. В этом случае метод Ланцоша можно использовать итерационным образом: после выполнения заданного числа шагов процесс прерывается и, если еще не все требуемые пары Ритца сошлись с требуемой точностью, то формируется новый начальный вектор <math style="vertical-align:-20%;>q_1</math>, являющийся линейной комбинацией векторов Ритца, еще не сошедшихся с заданной точностью, и процесс начинается заново.<ref>http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.5)</ref> | ||
== Вычислительное ядро алгоритма == | == Вычислительное ядро алгоритма == | ||
− | Вычислительное ядро рассматриваемого алгоритма (наиболее ресурсно-затратная часть алгоритма) - формирование на каждом шаге цикла промежуточного вектора <math>z</math>, вычисляемого по формуле: <math>z = A\,q_j</math> | + | Вычислительное ядро рассматриваемого алгоритма (наиболее ресурсно-затратная часть алгоритма) - формирование на каждом шаге цикла промежуточного вектора <math>z</math>, вычисляемого по формуле: <math>z = A\,q_j</math>. Данная операция, по сравнению с другими операциями алгоритма, затратна и требовательна, как с точки зрения количества производимых операций, так и с точки зрения объема оперируемых данных. <br><br> |
+ | Например, умножение матрицы размера <math style="vertical-align:-10%>n\times n</math> на вектор длины <math style="vertical-align:0%>n</math> требует: <math style="vertical-align:-20%>n^2+(n-1)n = 2n^2-n</math> операций умножения и сложения. В свою очередь аналогичная операция умножения матрицы <math style="vertical-align:-20%>(n+1)\times (n+1)</math> на вектор длины <math style="vertical-align:-20%>(n+1)</math> требует: <math style="vertical-align:-10%>2n^2+3n+1</math> операций умножения и сложения. То есть повышение размерности задачи всего на 1 увеличивает число необходимых действий в этом шаге алгоритма на: <math style="vertical-align:-10%>4n+1</math>. <br><br> | ||
+ | Так же, стоит помнить, что, согласно разделу 1.2, данную операцию умножения матрицы на вектор необходимо выполнить <math style="vertical-align:-10%>k</math> раз. Нетрудно понять, насколько возрастает и колоссален масштаб операций, если в задачах, где критична точность, размерности <math style="vertical-align:0%>n</math> могут иметь порядок <math style="vertical-align:-10%>10^5</math> или даже более. | ||
== Макроструктура алгоритма == | == Макроструктура алгоритма == | ||
Строка 66: | Строка 86: | ||
Умножение матрицы на вектор - весьма дешевая и нетривиальная операция, если предполагать, что исходная матрица <math style="vertical-align:0%;>A</math> разреженная. Именно она подлежит оптимизации с использованием техник распараллеливания, поскольку она является вычислительным ядром алгоритма, а весь упомянутый процесс построения матрицы <math style="vertical-align:-30%;>T_j</math> выполняется последовательно. | Умножение матрицы на вектор - весьма дешевая и нетривиальная операция, если предполагать, что исходная матрица <math style="vertical-align:0%;>A</math> разреженная. Именно она подлежит оптимизации с использованием техник распараллеливания, поскольку она является вычислительным ядром алгоритма, а весь упомянутый процесс построения матрицы <math style="vertical-align:-30%;>T_j</math> выполняется последовательно. | ||
− | + | Рассмотрим вторую часть алгоритма - поиск собственных значений сформированной матрицы <math style="vertical-align:-30%;>T_j</math>.<br> | |
+ | Далее, наглядно, в виде псевдокода, представлен, упомянутый в разделе 1.2, QR-алгоритм (аналогично можно рассмотреть и QL-алгоритм) со сдвигами Релэя, который весьма популярен на практике. | ||
+ | <br> | ||
+ | |||
+ | <math> | ||
+ | \begin{align} | ||
+ | \mathbf{Input}: \;&tridiagonal\;\;matrix \;T\;with\;\;n\times n\;\;size\\ | ||
+ | T^{(0)}&:=T\\ | ||
+ | \mathbf{for}& \;\;m=n,...,2 \;\; \mathbf{do}\\ | ||
+ | &k=0\\ | ||
+ | & \mathbf{repeat}\\ | ||
+ | & \quad \;\; k=k+1\\ | ||
+ | & \quad \;\; \mu^{(k)}=T_{m,m}^{(k-1)}\\ | ||
+ | & \quad \;\; Q^{(k)}R^{(k)}=T^{(k-1)}-\mu^{(k)}I\;\;using\;\;QR\;decomposition\\ | ||
+ | & \quad \;\; T^{(k)}=R^{(k)}Q^{(k)}+\mu^{(k)}I\\ | ||
+ | & \mathbf{until} \;\;\; |T_{m,m-1}^{(k)}| \;is\;\;small\;\;enough\\ | ||
+ | & Save \;\;T_{m,m}^{(k)} \;\;as\;\; converged\;\;eigenvalue\;of\;T\\ | ||
+ | & Remove \;\boldsymbol{n}\,th\;row\;and\;\boldsymbol{n}\,th\;column\;\;from \;T \\ | ||
+ | & and\;take\;this\;new\;cropped\;matrix\;as\;new\;T^{(0)}\;with\;\;(n-1)\times (n-1)\;\;size\\ | ||
+ | \mathbf{end}&\; \mathbf{for} | ||
+ | \end{align} | ||
+ | </math> | ||
+ | <br> | ||
+ | Малость наддиагональных и поддиагональных элементов матрицы (фраза ''"small enough"'' в псевдокоде) подразумевает: | ||
+ | <math style="vertical-align:-30%;> |T_{m,m-1}^{(k)}| \leq \varepsilon\,|T_{m,m}^{(k)}| \quad\quad </math> , где <math style="vertical-align:0%;> \varepsilon </math> - заданная точность<br> | ||
+ | Также вместо сдвига Релэя, обозначенного в алгоритме через <math style="vertical-align:-20%;>\mu^{(k)}</math>, часто на практике используется сдвиг по Уилкинсону, который даёт гарантированную сходимость внедиагональных элементов матрицы <math style="vertical-align:0%;> T^{(k)} </math>, формируемой на каждом шаге, к нулю, при этом жертвуя монотонностью их убывания.<ref>Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 378, вторая половина страницы)</ref><ref>Парлетт Б. Симметричная проблема собственных значений. Численные методы.,: Мир, 1983. с. 169</ref><br> | ||
+ | Подробнее с различными сдвигами и соответствующими оценками скоростей и количествами операций можно ознакомиться по указанной ссылке:<ref>Парлетт Б. Симметричная проблема собственных значений. Численные методы.,: Мир, 1983. с. 179-182</ref>. | ||
+ | <br><br>Для совершения QR-декомпозиции на каждом шаге может использоваться любой из алгоритмов по ссылке.<ref>https://en.wikipedia.org/wiki/QR_decomposition</ref> Подробные описания этих алгоритмов также доступны на данном ресурсе algowiki-project.<br> | ||
+ | Так как мы оперируем не обычной матрицей и даже не Хессенберговой, а симметричной и трёхдиагональной, то скорость таких алгоритмов значительно возрастёт. Например, согласно данному ресурсу <ref>http://algorithm.narod.ru/ln/eigen/ETridiag.html</ref>, для QL-алгоритма с неявными сдвигами:<br> | ||
+ | Для трёхдиагональной матрицы объем арифметических действий составляет <math> O(n)</math> на одну итерацию вместо <math> O(n^3)</math> для матрицы общего вида, а число итераций для нахождения первых собственных значений примерно равно 4 - 5. Но на этих итерациях также уменьшаются внедиагональные элементы правого нижнего угла. И, таким образом, дальнейшие собственные значения ищутся значительно быстрее. Среднее число итераций на каждое собственное значение обычно составляет 1.3 - 1.6.<br> | ||
+ | Аналогично QL, QR-разложение трёхдиагольной матрицы также требует <math> O(n)</math> флопов<ref>Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 378, начало раздела 8.2.2)</ref><br> | ||
+ | |||
+ | Подводя итог, во второй части алгоритма Ланцоша можно выделить следующие макрооперации: | ||
+ | * умножение матрицы на вещественное число; | ||
+ | * перемножение матриц; | ||
+ | * умножение и сравнение вещественных чисел; | ||
+ | * + набор других макроопераций в зависимости от выбора метода, с помощью которого будет совершаться сама QR или QL-декомпозиция (выше продемонстрированы, уже, как минимум, 3 разных способа). | ||
+ | Так же, важно заметить, что набор макропераций может быть несколько другим, если выбрать какой-либо иной современный метод поиска собственных чисел трёхдиагональной матрицы, не использующий QR и QL разложения(факторизацию). Два таких метода были упомянуты в пункте 1.2. | ||
== Схема реализации последовательного алгоритма == | == Схема реализации последовательного алгоритма == | ||
− | С целью полностью не дублировать | + | С целью полностью не дублировать раздел 1.2 данной статьи, где представлен наглядный и доступный для понимания псевдокод алгоритма, постараемся лишь коротко просуммировать и обобщить весь перечень последовательных действий в рассматриваемом алгоритме. |
В качестве входных данных имеем: вещественная симметричная матрица <math style="vertical-align:0%;>A</math> размера <math style="vertical-align:-10%>n\times n</math>, известный вещественный вектор <math style="vertical-align:0%;>b</math> длины <math style="vertical-align:0%>n</math> и число <math style="vertical-align:0%>k<n</math>. | В качестве входных данных имеем: вещественная симметричная матрица <math style="vertical-align:0%;>A</math> размера <math style="vertical-align:-10%>n\times n</math>, известный вещественный вектор <math style="vertical-align:0%;>b</math> длины <math style="vertical-align:0%>n</math> и число <math style="vertical-align:0%>k<n</math>. | ||
Строка 75: | Строка 132: | ||
Далее: | Далее: | ||
* Инициализируем вещественную константу <math style="vertical-align:-20%;>\beta_0</math> и векторы <math style="vertical-align:-10%;>q_0</math> и <math style="vertical-align:-10%;>q_1</math> | * Инициализируем вещественную константу <math style="vertical-align:-20%;>\beta_0</math> и векторы <math style="vertical-align:-10%;>q_0</math> и <math style="vertical-align:-10%;>q_1</math> | ||
− | * Итерационно для всех <math style="vertical-align:-20%>j= | + | * Итерационно для всех <math style="vertical-align:-20%>j=1,...,k</math>: |
** Вычисляем вспомогательный вектор <math style="vertical-align:0%>z</math>, используя умножение матрицы на вектор | ** Вычисляем вспомогательный вектор <math style="vertical-align:0%>z</math>, используя умножение матрицы на вектор | ||
** Вычисляем, используя скалярное произведение векторов, значение <math style="vertical-align:-30%>\alpha_j</math> - элемент на главной диагонали трёхдиагональной матрицы <math style="vertical-align:-30%;>T_j</math> | ** Вычисляем, используя скалярное произведение векторов, значение <math style="vertical-align:-30%>\alpha_j</math> - элемент на главной диагонали трёхдиагональной матрицы <math style="vertical-align:-30%;>T_j</math> | ||
** Вычисляем по формуле новое значение и перезаписываем вектор <math style="vertical-align:0%>z</math> | ** Вычисляем по формуле новое значение и перезаписываем вектор <math style="vertical-align:0%>z</math> | ||
** Вычисляем значение <math style="vertical-align:-20%>\beta_j</math> - элементы непосредственно над и под главной диагональю той же матрицы <math style="vertical-align:-30%;>T_j</math> | ** Вычисляем значение <math style="vertical-align:-20%>\beta_j</math> - элементы непосредственно над и под главной диагональю той же матрицы <math style="vertical-align:-30%;>T_j</math> | ||
− | ** Вычисляем | + | ** Вычисляем, зная вектор <math style="vertical-align:0%>z</math>, очередной столбец матрицы <math style="vertical-align:-20%>Q</math>, он же вектор Ланцоша : <math style="vertical-align:-20%>\,\,q_{j+1}</math> |
− | ** Теперь, когда матрица <math style="vertical-align:-30%;>T_j</math> сформирована на очередном шаге, находим её собственные значения и вектора, | + | ** Теперь, когда матрица <math style="vertical-align:-30%;>T_j</math> сформирована на очередном шаге, находим её собственные значения и вектора любым доступным способом, о чём было подробно сказано в пункте 1.2 |
** Переходим на следующую итерацию: <math style="vertical-align:-20%>j</math>++ | ** Переходим на следующую итерацию: <math style="vertical-align:-20%>j</math>++ | ||
== Последовательная сложность алгоритма == | == Последовательная сложность алгоритма == | ||
− | Оценим количество операций и сложность последовательного алгоритма, изложенного в предыдущем | + | Оценим количество операций и сложность последовательного алгоритма, изложенного в предыдущем разделе. |
*Для вычисления вектора <math style="vertical-align:0%>z</math> умножается матрица размера <math style="vertical-align:-10%>n\times n</math> на вектор длины <math style="vertical-align:0%>n</math>, и потребуется <math style="vertical-align:0%>n^2</math> операций умножения и <math style="vertical-align:0%>n^2</math> операций сложения. | *Для вычисления вектора <math style="vertical-align:0%>z</math> умножается матрица размера <math style="vertical-align:-10%>n\times n</math> на вектор длины <math style="vertical-align:0%>n</math>, и потребуется <math style="vertical-align:0%>n^2</math> операций умножения и <math style="vertical-align:0%>n^2</math> операций сложения. | ||
*Умножение векторов <math style="vertical-align:-20%>q^T_j</math> и <math style="vertical-align:0%>z</math> длины <math style="vertical-align:0%>n</math> потребует <math style="vertical-align:0%>n</math> операций умножения и <math style="vertical-align:0%>n</math> операций сложения. | *Умножение векторов <math style="vertical-align:-20%>q^T_j</math> и <math style="vertical-align:0%>z</math> длины <math style="vertical-align:0%>n</math> потребует <math style="vertical-align:0%>n</math> операций умножения и <math style="vertical-align:0%>n</math> операций сложения. | ||
Строка 91: | Строка 148: | ||
*Умножение вектора длины <math>n</math> на вещественное число требует <math style="vertical-align:0%>n</math> операций умножения. | *Умножение вектора длины <math>n</math> на вещественное число требует <math style="vertical-align:0%>n</math> операций умножения. | ||
*Нахождение квадратичной нормы вектора <math style="vertical-align:0%>z</math> длины <math style="vertical-align:0%>n</math> требует <math style="vertical-align:0%>n</math> умножений и <math style="vertical-align:0%>n</math> сложений и ещё 1 операцию извлечения квадратного корня. | *Нахождение квадратичной нормы вектора <math style="vertical-align:0%>z</math> длины <math style="vertical-align:0%>n</math> требует <math style="vertical-align:0%>n</math> умножений и <math style="vertical-align:0%>n</math> сложений и ещё 1 операцию извлечения квадратного корня. | ||
− | *Заключительное нахождение собственных значений и собственных векторов трёхдиагональной матрицы <math style="vertical-align:-30%>T_j</math> размера <math style="vertical-align:-20%>j\times j</math> с помощью QR-алгоритма потребует в худшем случае <math style="vertical-align:-30%>O(j^3)</math> операций.<ref>http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.2)</ref> | + | *Заключительное нахождение собственных значений и собственных векторов трёхдиагональной матрицы <math style="vertical-align:-30%>T_j</math> размера <math style="vertical-align:-20%>j\times j</math> с помощью QR-алгоритма потребует в худшем случае <math style="vertical-align:-30%>O(j^3)</math> операций.<ref>http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.2, "Скорость сходимости при этом всегда не хуже квадратичной и почти всегда лучше кубической.")</ref> |
Посчитаем теперь суммарное количество простейших операций на одной итерации алгоритма (без учёта записей в память): | Посчитаем теперь суммарное количество простейших операций на одной итерации алгоритма (без учёта записей в память): | ||
Строка 98: | Строка 155: | ||
*1 операция извлечения квадратного корня<br> | *1 операция извлечения квадратного корня<br> | ||
Отдельно после всех итераций при <math style="vertical-align:-20%>j=k</math> : | Отдельно после всех итераций при <math style="vertical-align:-20%>j=k</math> : | ||
− | *<math style="vertical-align:-30%>O(k^3)</math> операций для поиска собственных значений и собственных векторов трёхдиагональной матрицы <math style="vertical-align:- | + | *<math style="vertical-align:-30%>O(k^3)</math> операций для поиска собственных значений и собственных векторов трёхдиагональной матрицы <math style="vertical-align:-20%>T_k</math> |
Итого можно утверждать следующее: | Итого можно утверждать следующее: | ||
Строка 107: | Строка 164: | ||
== Информационный граф == | == Информационный граф == | ||
− | На | + | На рис. 1 продемонстрирован граф одной итерации (при каком-либо произвольном значении итератора <math style="vertical-align:-20%>j</math>) описанного алгоритма без отображения входных и выходных данных. Наглядно продемонстрированы связи между всеми действиями, и с помощью деления на <math style="vertical-align:0%>n</math> потоков показано, какие операции возможно выполнять параллельно на каждом шаге с целью оптимизации и экономии машинного времени. В результате, после параллельно выполненных операций '''Division''' на заключительном ярусе, на выходе имеем значение следующего вектора Ланцоша <math style="vertical-align:-20%>q_{j+1}</math>, после чего следует переход на следующую итерацию, и процесс повторяется. |
− | [[Файл:Levin_graph.png|600px|thumb|center|'''Simp''' (от англ. simple) - операции сложения и умножения вещественных чисел при вычислении произведения матрицы на вектор;<br><br> | + | [[Файл:Levin_graph.png|600px|thumb|center|Рис. 1 Структура одной итерации алгоритма]] <br> |
+ | Обозначения на рисунке: <br> | ||
+ | '''Simp''' (от англ. simple) - операции сложения и умножения вещественных чисел при вычислении произведения матрицы на вектор;<br><br> | ||
'''Vec mult''' (от англ. vectors multiplication) - операция скалярного умножения двух векторов;<br><br> | '''Vec mult''' (от англ. vectors multiplication) - операция скалярного умножения двух векторов;<br><br> | ||
− | '''Vec subtr''' (от англ. vectors subtraction, из-за использованных в операции вычитаний векторов) - операция умножения вектора на число (выполняется дважды) и формирование нового значения <math style="vertical-align: | + | '''Vec subtr''' (от англ. vectors subtraction, из-за использованных в операции вычитаний векторов) - операция умножения вектора на число (выполняется дважды) и формирование нового значения <math style="vertical-align:-10%>z_{new}</math> по формуле: <math style="vertical-align:-30%>z_{new} = z - \alpha_j q_j - \beta_{j-1}q_{j-1} \;</math>;<br><br> |
<math>||\cdot||</math> - операция вычисления нормы вектора;<br><br> | <math>||\cdot||</math> - операция вычисления нормы вектора;<br><br> | ||
− | '''Division''' - операция деления вектора на вещественное число <math style="vertical-align:-30%>\beta_j</math> | + | '''Division''' - операция деления вектора на вещественное число <math style="vertical-align:-30%>\beta_j</math> <br><br> |
− | Важно отметить, что упомянутые выше операции также легко поддаются оптимизации. Например, попарные умножения вещественных координат векторов при вычислении скалярного произведения также легко выполняются параллельно на <math style="vertical-align:0%>n</math> потоках, а затем можно применить суммирование методом сдваивания, о котором сказано в следующем | + | Важно отметить, что упомянутые выше операции также легко поддаются оптимизации. Например, попарные умножения вещественных координат векторов при вычислении скалярного произведения также легко выполняются параллельно на <math style="vertical-align:0%>n</math> потоках, а затем можно применить суммирование методом сдваивания, о котором сказано в следующем разделе. Умножение или деление вектора на вещественное число являющееся, по определению, умножением или делением всех его координат на это число тоже может быть выполнено эффективнее, если мы используем <math style="vertical-align:0%>n</math> потоков, а не выполняем эти действия последовательно. |
== Ресурс параллелизма алгоритма == | == Ресурс параллелизма алгоритма == | ||
Параллельные операции возможны только внутри итераций, так как рассматриваемый алгоритм является итерационным, и сами итерации строго последовательны.<br> | Параллельные операции возможны только внутри итераций, так как рассматриваемый алгоритм является итерационным, и сами итерации строго последовательны.<br> | ||
− | Рассмотрим в этом | + | Рассмотрим в этом разделе подробнее, какой выигрыш мы можем получить при распараллеливании операций внутри одной итерации согласно графу из предыдущего раздела. |
Умножение вещественной симметричной матрицы <math style="vertical-align:0%;>A</math> размера <math style="vertical-align:-10%>n\times n</math> на вектор <math style="vertical-align:0%;>b</math> длины <math style="vertical-align:0%>n</math> требует последовательного выполнения <math style="vertical-align:0%>n</math> ярусов умножений и сложений. Сложение элементов вектора длины <math style="vertical-align:0%>n</math> на каждом шаге перемножения можно оптимизировать и выполнить за <math style="vertical-align:-20%>\log_2 n</math> действий, если применять метод сдваивания. | Умножение вещественной симметричной матрицы <math style="vertical-align:0%;>A</math> размера <math style="vertical-align:-10%>n\times n</math> на вектор <math style="vertical-align:0%;>b</math> длины <math style="vertical-align:0%>n</math> требует последовательного выполнения <math style="vertical-align:0%>n</math> ярусов умножений и сложений. Сложение элементов вектора длины <math style="vertical-align:0%>n</math> на каждом шаге перемножения можно оптимизировать и выполнить за <math style="vertical-align:-20%>\log_2 n</math> действий, если применять метод сдваивания. | ||
Строка 124: | Строка 183: | ||
Дальнейшие операции выполняются последовательно, а вычисление значений векторов происходит за один ярус операций сложения или умножения. | Дальнейшие операции выполняются последовательно, а вычисление значений векторов происходит за один ярус операций сложения или умножения. | ||
− | Ресурс параллелизма алгоритма вычисления собственных значений построенной трёхдиагональной матрицы <math style="vertical-align:-20%>T_k</math> размера <math style="vertical-align:0%>k\times k</math> зависит от выбранного алгоритма (об этих алгоритмах подробнее было сказано в | + | Ресурс параллелизма алгоритма вычисления собственных значений построенной трёхдиагональной матрицы <math style="vertical-align:-20%>T_k</math> размера <math style="vertical-align:0%>k\times k</math> зависит от выбранного алгоритма (об этих алгоритмах подробнее было сказано в разделах 1.2 и 1.4). Будет очень затратно с точки зрения объёма материала пытаться рассмотреть пусть даже часть этих методов в этой статье, а так же тонкости их распараллеливания. Предлагаем читателям при желании самим ознакомиться с этими алгоритмами на данном ресурсе или прибегнув к иным источникам. |
− | При классификации по высоте ЯПФ, таким образом, алгоритм Ланцоша без переортогонализации относится к алгоритмам с ''логарифмической сложностью'', и его сложность равна <math style="vertical-align:-30%>O(\log_2 n)</math> с важным замечанием, что это сложность только одной итерации, а максимум в алгоритме может быть выполнено последовательно <math style="vertical-align:0%>k</math> таких однотипных итераций. <br> | + | При классификации по высоте ЯПФ, таким образом, алгоритм Ланцоша без переортогонализации относится к алгоритмам с ''логарифмической сложностью'', и его сложность равна <math style="vertical-align:-30%>O(\log_2 n)</math> с важным замечанием, что это сложность только одной итерации, а максимум в алгоритме может быть выполнено последовательно <math style="vertical-align:0%>k</math> таких однотипных итераций, если не будет осуществлён ранний выход из цикла. <br> |
− | Несмотря на то, что на графе в предыдущем | + | Несмотря на то, что на графе в предыдущем разделе для лучшей визуализации и понимания было изображено <math style="vertical-align:0%>n</math> потоков (никаких допущений мы не делали и нарушений с точки зрения логики и математики нет, можно изобразить большее число потоков, просто часть времени некоторые из них могут бездействовать и не использоваться), на самом деле правильным и разумным будет реализовать начальное параллельное выполнение <math style="vertical-align:0%>n^2</math> операций умножения всех вещественных элементов матрицы <math style="vertical-align:0%>A</math> на соответствующие элементы вектора <math style="vertical-align:-30%>q_j</math>, после чего применять тот же самый упомянутый метод сдваивания. <br><br> |
Поэтому при классификации по ширине ЯПФ его сложность будет ''квадратичной'' и равна <math style="vertical-align:-30%>O(n^2)</math>. | Поэтому при классификации по ширине ЯПФ его сложность будет ''квадратичной'' и равна <math style="vertical-align:-30%>O(n^2)</math>. | ||
== Входные и выходные данные алгоритма == | == Входные и выходные данные алгоритма == | ||
− | '''Входные данные алгоритма:''' вещественная симметричная <math style="vertical-align:0%;>A</math> размера <math style="vertical-align:-10%>n\times n</math>, вещественный вектор <math style="vertical-align:0%;>b</math> длины <math style="vertical-align:0%>n</math>, и одно | + | '''Входные данные алгоритма:''' вещественная симметричная <math style="vertical-align:0%;>A</math> размера <math style="vertical-align:-10%>n\times n</math>, вещественный вектор <math style="vertical-align:0%;>b</math> длины <math style="vertical-align:0%>n</math>, и одно целое число <math style="vertical-align:-10%>k</math>, означающее количество итераций. |
− | '''Объём входных данных:''' <math style="vertical-align:-10%;>n^2 +n + 1 </math>. Если учесть, что матрица симметричная и достаточно для её однозначного определения задать элементы на главной диагонали и элементы над или под ней, то можно сократить объём входных данных с целью экономии памяти до: <math>\ \frac{n | + | '''Объём входных данных:''' <math style="vertical-align:-10%;>n^2 +n + 1 </math>. Если учесть, что матрица симметричная и достаточно для её однозначного определения задать элементы на главной диагонали и элементы над или под ней, то можно сократить объём входных данных с целью экономии памяти до: <math>\ \frac{n^2-n}{2}+n+n+1 =\frac{n^2+3n}{2} + 1</math> |
− | '''Выходные данные алгоритма:''' вектор собственных значений <math style="vertical-align:0%;>\Theta^k</math> длины <math style="vertical-align:0%>k</math>, матрица | + | '''Выходные данные алгоритма:''' вектор собственных значений <math style="vertical-align:0%;>\Theta^k</math> длины <math style="vertical-align:0%>k</math>, матрица <math style="vertical-align:0%>S^k</math> из соответствующих собственных векторов размера <math style="vertical-align:0%>n\times k</math>. |
'''Объём выходных данных:''' <math>k\;(n + 1)</math>. | '''Объём выходных данных:''' <math>k\;(n + 1)</math>. | ||
== Свойства алгоритма == | == Свойства алгоритма == | ||
− | + | В данном разделе перечислены без какой-либо хронологии или связи друг с другом наиболее важные и разнообразные свойства алгоритма, на которые стоит и полезно обратить внимание, а также которые выгодно отличают его от схожих алгоритмов, решающих ту же задачу.<br> | |
+ | 1) Отношение последовательной сложности алгоритма к параллельной,с учётом <math style="vertical-align:0%>k</math> итераций, равно <math>\;\;\frac{kn^2}{k \log_2{n}}=\frac{n^2}{\log_2{n}}</math>;<br> | ||
+ | 2) Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных, равна <math style="vertical-align:-70%>\;\;\frac{k\,n^2}{0.5\,n^2+1.5\,n+k\,n+k+1}</math> и <math style="vertical-align:-10%>\approx 2\,k</math>, так как на практике верно отношение <math style="vertical-align:0%>k<<n</math> ;<br><br> | ||
+ | 3) Для собственных значений формируемых матриц <math style="vertical-align:-20%>T_j</math> верно отношение (следствие теоремы Коши о перемежаемости): <math style="vertical-align:-30%>\lambda_i(T_{k+1})\geq \lambda_i(T_{k})\geq \lambda_{i+1}(T_{k+1})\geq \lambda_{i+1}(T_{k})</math> ;<ref>James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 383)</ref><br><br> | ||
+ | 4) Крайние (наибольшие и наименьшие) собственные значения матриц <math style="vertical-align:-20%>T_j</math> сходятся к крайним собственным значениям матрицы <math style="vertical-align:0%>A</math> первыми (это часто происходит уже на ранних шагах при <math style="vertical-align:-20%>j\approx 2\,\sqrt{n}</math><ref>http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.5)</ref>), а собственные значения в середине спектра - последними;<br><br> | ||
+ | 5) Из-за ограниченной точности постепенно теряется ортогональность вектора Ланцоша <math style="vertical-align:-20%>q_j</math> к предыдущим векторам Ланцоша, поэтому необходимо примерно каждые 10-15 итераций проводить дорогостоящую операцию реортогонализации, но это уже будет иной алгоритм с очень малым различием в одной операции и в программном коде, реализующем его, соответственно; <ref>Sam Handler - The Lanczos Algorithm For Large-Scale Eigenvalue Problems (08.01.07), slide №8</ref><br><br> | ||
+ | 6) Эффективность и быстрота выполнения алгоритма очень сильно зависит от скорости памяти (диска). Согласно тесту только ''6%'' времени работы программы приходится на вычисления, остальное время затрачивается на ожидание отклика диска;<ref>Sam Handler - The Lanczos Algorithm For Large-Scale Eigenvalue Problems (08.01.07), slide №10</ref><br><br> | ||
+ | 7) Метод Ланцоша удобен тем, что не требует хранения исходной матрицы полным массивом: метод использует исходную матрицу только в операциях умножения матрицы на вектор, что позволяет эффективно использовать разреженность матрицы или регулярность структуры матрицы. Поэтому метод Ланцоша может быть использован для матриц таких больших порядков, когда методы вращений и отражений не могут быть применены. | ||
= Программная реализация алгоритма = | = Программная реализация алгоритма = | ||
Строка 156: | Строка 222: | ||
== Масштабируемость алгоритма и его реализации == | == Масштабируемость алгоритма и его реализации == | ||
− | + | Для исследования масштабируемости рассматриваемого алгоритма Ланцоша без переортогонализации автором была реализована программа на языке С++ с использованием технологии MPI. <ref>https://goo.gl/pNOFmW или альтернативная ссылка с прикреплённым кодом: https://goo.gl/9AapM6 , по просьбе на почту я (автор статьи) готов предоставить желающим доступ к проекту с этим кодом на ресурсе Bitbucket</ref> Дальнейшее исследование было проведено на суперкомпьютере "Ломоносов" Суперкомпьютерного комплекса МГУ.<ref>https://parallel.ru/cluster/lomonosov.html</ref> <br> Важно отметить, что реализованная программа выполняет только первую часть алгоритма - формирование трёхдиагональной матрицы <math >T_j</math>. Вторая часть алгоритма (задача поиска собственных значений матрицы <math >T_j</math>) может быть решена несколькими методами, каждый из которых обладает своей эффективностью распараллеливания и характерными свойствами. Подробно этот вопрос уже обсуждался в статье ранее, поэтому не будем ещё раз заострять на этом внимание и останавливаться. | |
+ | <br><br> | ||
+ | Сборка осуществлялась со следующими параметрами: | ||
+ | * Компилятор intel/15.0.090 | ||
+ | * Openmpi/1.8.4-icc | ||
+ | В серии проведённых расчётов рассматривались следующие числовые значения параметров: | ||
+ | * Размер <math style="vertical-align:0%;>n</math> задачи и, соответственно, матрицы <math style="vertical-align:0%;>A</math>, задействованной в операции умножения на вектор: [2000 : 30000] с шагом 1000 | ||
+ | * Число <math style="vertical-align:-20%;>p</math> процессоров: 1, 2, 4, 16, 32, 48, 64, 96, 128, 192, 256 | ||
+ | * Число итераций в алгоритме: <math style="vertical-align:0%;>k=350</math> | ||
+ | Число <math style="vertical-align:0%;>k</math> взято таким вопреки информации в начале статьи, где говорится, что значение <math style="vertical-align:0%;>k</math> редко превышает <math style="vertical-align:-10%;>10^2</math> (хоть мы и имеем право брать его любым по нашему усмотрению). Это сделано исключительно для лучшей визуализации пиков на графиках в данном разделе и наглядности получаемых результатов, так как при меньших на порядок значениях параметра <math style="vertical-align:0%;>k</math> времена выполнения программ были слишком малы даже при минимальных числах процессоров и максимальных размерах <math style="vertical-align:0%;>n</math> задачи. | ||
+ | <br> | ||
+ | На рис. 2 изображён график зависимости времени выполнения программы от числа процессоров и размера <math style="vertical-align:0%;>n</math> задачи. <br> | ||
+ | {|align="center" | ||
+ | |-valign="top" | ||
+ | |[[file:Levin_task1_execTIME.png|620px|thumb|center|Рис. 2 График зависимости времени выполнения программы.]] | ||
+ | |[[file:Levin604 task1 result EFFICIENCY.png|630px|thumb|center|Рис. 3 График зависимости эффективности распараллеливания программы.]] | ||
+ | |} | ||
+ | Многочисленные тесты показали при малых количествах ядер уменьшение времени выполнения программы почти в 2 раза при увеличении числа ядер в 2 раза на всём диапазоне размеров матриц, что и отражает сильный излом на первом графике. Изменение значений времени можно легко оценить по предоставленной цветовой шкале. | ||
+ | Был построен график эффективности распараллеливания (parallel efficiency)<ref>https://goo.gl/WCNEjR</ref> в зависимости от числа процессоров и размера задачи, изображённый на рис. 3. | ||
+ | Получены следующие результаты численных экспериментов: | ||
+ | * Средняя эффективность распараллеливания программы составила: 42.5576% ; | ||
+ | * Минимальная эффективность реализации: 0.674% (число процессоров 256 и минимальный размер матрицы 2000); | ||
+ | * Максимальная эффективность реализации: 77.773% (число процессоров 2, размер матрицы 20000). | ||
+ | Нужно понимать, что это лишь экстремумы, соответствующие двум экспериментам, которые сами по себе не дают полной картины и не позволяют однозначно судить о параллельных качествах алгоритма и реализующей его программы при столь большом числе параметров и проводимых расчётов. <br>На основании рис. 3 можно отметить следующие значимые и важные факты: | ||
+ | *Имеется ярко выраженный спад эффективности при минимальном рассматриваемом размере матрицы <math style="vertical-align:0%;>n=2000</math> вдоль всей оси OY, отвечающей за число процессоров; | ||
+ | *Присутствуют два пика эффективности (жёлтого цвета на рис. 3): при числе <math style="vertical-align:-20%;>p</math> процессоров 2 и 128. Затем при дальнейшем увеличении числа процессоров с 128 до 256 наблюдается постепенное уменьшение эффективности реализации. Это связано с увеличением накладных расходов и затрат времени на обмены сообщениями между процессами. | ||
== Динамические характеристики и эффективность реализации алгоритма == | == Динамические характеристики и эффективность реализации алгоритма == | ||
Строка 164: | Строка 255: | ||
== Существующие реализации алгоритма == | == Существующие реализации алгоритма == | ||
+ | Несмотря на то, что алгоритм является далеко не самым популярным, алгоритмом, про который нельзя сказать, что он всегда «на слуху», на сегодняшний день существует множество реализаций на различных популярных языках.<br> | ||
+ | Перечислим далее некоторые из них, указывая язык программирования, лежащий в их основе, и некоторые важные характеристики, которые обсуждались в статье ранее: | ||
+ | *''Code on netlib.org by Jane Cullum and Ralph Willoughby'' ('''Fortran 77'''; без реортогонализации векторов; без реализации распараллеливания)<ref>http://www.netlib.org/lanczos/leval</ref> | ||
+ | *''Lanczos algorithm on freesourcecode.net'' ('''Matlab'''; присутствует реортогонализация векторов; без реализации распараллеливания)<ref>http://freesourcecode.net/matlabprojects/61741/lanczos-algorithm--in-matlab</ref> | ||
+ | *''Lanczos for eigenvalues in Numerical Linear Algebra, Spring 2007'' ('''Matlab'''; частичная или полная реортогонализация - доступны оба варианта; без реализации распараллеливания)<ref>Ссылки на файлы lanso.m и lanfu.m можно найти на https://www.nada.kth.se/~ruhe/2D5219/labs2007.html</ref> | ||
+ | *''Planso'' (название происходит от parallel Lanso.f) ''code by Kesheng Wu and Horst D. Simon'' ('''Fortran 77'''; частичная реортогонализация векторов; использование MPI для коммуникаций)<ref>https://github.com/jiahao/planso.jl/tree/master/external/PLAN/plan К сожалению, ссылка в описании пакета на github, ведущая на сайт National Energy Research Scientific Computing Center (NERSC), с более подробной информацией о данной программе больше не активна и выдаёт результат ''Page not found''</ref> | ||
+ | * ''Lanczos.cpp in the Vienna Computing Library'' ('''C++''', частичная реортогонализация, без реализации распараллеливания) <ref>http://viennacl.sourceforge.net/doc/lanczos_8cpp_source.html</ref> | ||
+ | * ''Parallel Eigen Values code using C++ AMP on microsoft msdn blog'' ('''C++'''; ? ; распараллеливание есть и реализовано через C++ AMP) <ref>https://blogs.msdn.microsoft.com/nativeconcurrency/2013/12/20/eigen-values/ Подробнее о C++ Accelerated Massive Parallelism можно почитать здесь: https://msdn.microsoft.com/ru-ru/library/hh265137(v=vs.140).aspx или здесь: http://professorweb.ru/my/csharp/optimization/level4/4_6.php </ref> | ||
= Литература = | = Литература = | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
[[en:Description of algorithm properties and structure]] | [[en:Description of algorithm properties and structure]] |
Текущая версия на 17:01, 19 декабря 2016
Эта работа успешно выполнена Преподавателю: в основное пространство, в подстраницу Данное задание было проверено и зачтено. Проверено Konshin и ASA. |
Основные авторы описания: Левин А.Д.
Алгоритм Ланцоша для точной арифметики (без переортогонализации) | |
Последовательный алгоритм | |
Последовательная сложность | [math]O(k\,n^2)[/math] |
Объём входных данных | [math]\frac{n^2+3n}{2} + 1[/math] |
Объём выходных данных | [math]k\;(n + 1)[/math] |
Параллельный алгоритм | |
Высота ярусно-параллельной формы | [math]O(k\log_2 n)[/math] |
Ширина ярусно-параллельной формы | [math]O(n^2)[/math] |
Содержание
- 1 Свойства и структура алгоритмов
- 1.1 Общее описание алгоритма
- 1.2 Математическое описание алгоритма
- 1.3 Вычислительное ядро алгоритма
- 1.4 Макроструктура алгоритма
- 1.5 Схема реализации последовательного алгоритма
- 1.6 Последовательная сложность алгоритма
- 1.7 Информационный граф
- 1.8 Ресурс параллелизма алгоритма
- 1.9 Входные и выходные данные алгоритма
- 1.10 Свойства алгоритма
- 2 Программная реализация алгоритма
- 2.1 Особенности реализации последовательного алгоритма
- 2.2 Локальность данных и вычислений
- 2.3 Возможные способы и особенности параллельной реализации алгоритма
- 2.4 Масштабируемость алгоритма и его реализации
- 2.5 Динамические характеристики и эффективность реализации алгоритма
- 2.6 Выводы для классов архитектур
- 2.7 Существующие реализации алгоритма
- 3 Литература
1 Свойства и структура алгоритмов
1.1 Общее описание алгоритма
Данный алгоритм появился в 1950 г. и носит имя венгерского физика и математика Корнелия Ланцоша (венг. Lánczos Kornél). Алгоритм Ланцоша относится к итерационным методам вычисления собственных значений для матриц столь больших порядков [math] n[/math], что к ним нельзя применить прямые методы из-за ограничений по времени и памяти.
Сам Ланцош указывал, что его метод предназначен для отыскания нескольких собственных векторов симметричных матриц, хотя к методу сразу было обращено внимание, как к способу приведения всей матрицы к трёхдиагональному виду. Двадцатью годами позже канадский математик Крис Пэж показал, что, несмотря на чувствительность к округлениям, алгоритм Ланцоша - эффективное средство вычисления некоторых [math]k[/math] собственных чисел и соответствующих им собственных векторов. [1] Обычно число [math]k[/math] берут в два раза больше, чем количество собственных значений матрицы, которые поставлена цель найти, и оно имеет порядок не более [math]10^2[/math].[2]
Алгоритм Ланцоша для вычисления собственных значений симметричной матрицы [math]A[/math] соединяет в себе метод Ланцоша для построения последовательности подпространств Крылова и ортонормированных векторов Ланцоша и процедуру Рэлея-Ритца получения оптимальных приближений собственных значений и соответствующих собственных векторов исходной матрицы [math]A[/math].[3]
В данной статье рассматривается вариант алгоритма Ланцоша, в котором опущено влияние ошибок округления на вычислительный процесс, хотя на практике этому посвящается отдельное внимание и существуют различные методы решения данной проблемы, такие как частичная или полная переортогонализация. Этим модифицированным методам посвящены отдельные статьи на данном ресурсе.
1.2 Математическое описание алгоритма
Обозначения и формулы, используемые в данном разделе, взяты из литературы, указанной по ссылке.[4]
Алгоритм Ланцоша для вычисления [math]k[/math] собственных значений и собственных векторов вещественной симметричной матрицы [math]A=A^T[/math] в точной арифметике: [5]
[math] \begin{align} q_1 = & \,\frac{b}{\|b\|_2},\; \beta_0 = 0,\; q_0 = 0\\ \mathbf{for} \; & j = 1 \; to \; k \,\; \mathbf{do} \\ & z = A\,q_j\\ & \alpha_j = q^T_j z\\ & z = z - \alpha_j q_j - \beta_{j-1}q_{j-1}\\ & \beta_j = \|z\|_2\\ & \mathbf{If} \; (\beta_j == 0) \; \mathbf{then}\; stop\; the\; algorithm \\ & \; q_{j+1} = \frac{z}{\beta_j} \\ & compute\; eigenvalues\; and \;eigenvectors\;of \;matrix \;\;T_j= Q^T_j A Q\;\;and\;estimate \;the\; errors\\ \mathbf{end} \; & \mathbf{for} \end{align} [/math]
В продемонстрированном выше алгоритме [math]b[/math] - заданный вещественный вектор. Также полагается известным алгоритм вычисления произведения матрицы [math]A[/math] на вектор [math]x[/math].
Введём матрицу Крылова, определяемую следующим соотношением: [math]K_j = [b,Ab,A^2b,...,A^{j-1}b][/math].
Далее, на практике, матрица [math]K[/math] заменяется матрицей [math]Q[/math], такой, что при любом числе [math]k[/math] линейные оболочки первых [math]k[/math] столбцов в [math]K[/math] и [math]Q[/math] являются одним и тем же подпространством.[6] Тогда матрица [math]Q[/math], в отличие от матрицы [math]K[/math], хорошо обусловлена и легко обратима. В результате получаем матрицу [math]Q_j = [q_1, q_2, \dots, q_j][/math] размерности [math]n\times j[/math], столбцы которой ортогональны, являются базисом подпространства Крылова и называются векторами Ланцоша.
В алгоритме Ланцоша вычислению подлежит столько первых столбцов в матрице [math]Q_j[/math], сколько необходимо для получения требуемого приближения к решению [math]A\,x\,=b\,\,(A\,x=\lambda \, x)[/math].
Получение нулевого [math]\beta_j[/math] в итерационном процессе - событие, желательное в том смысле, что оно свидетельствует о том, что найдено некоторое подпространство, являющееся в точности инвариантным, а все собственные значения матрицы [math]T_j[/math] являются собственными значениями матрицы [math]A[/math]. На практике же нулевое и близкие к нулю значения получаются редко.[7]
Затем на каждом шаге цикла формируется симметричная трёхдиагональная матрица [math]T_j = Q^T_j A Q[/math], к которой применяется процесс Рэлея-Ритца для поиска её собственных значений (на практике для поиска этих собственных значений можно использовать любой из специальных методов в параграфе книги по ссылке).[8]
Эти собственные значения, они же числа Ритца, и полагаются приближёнными собственными значениями исходной матрицы [math]A[/math].
Существует множество методов для отыскания собственных значений вещественной симметричной трехдиагональной матрицы. Большинство из них требует [math]O(n^2)[/math] операций [9], но существуют и быстрые алгоритмы, требующие лишь [math]O(n\ln n)[/math] операций.[10]
Одним из возможных способов отыскать собственные значения симметричной трехдиагональной матрицы - прямое вычисление корней характеристического полинома [math]p_n(\lambda)[/math] через метод деления пополам, где формируется последовательность Штурма и локализуются собственные числа, являющиеся корнями характеристического полинома. Нахождение всех [math]n[/math] собственных значений матрицы этим способом требует [math]2n^2t[/math] умножений и вычитаний, где [math]t[/math] - число сделанных шагов с применением метода деления пополам.[11] Соответствующие собственные вектора могут быть найдены посредством обратных итераций за [math] O(n) [/math] флопов. [12]
На практике, если требуется только небольшая часть от всей совокупности собственных векторов и значений, и матрица имеет Хессенбергову или трёхдиагональную форму, очень эффективными будут методы факторизации, как, например, QR-алгоритм или QL-алгоритм со сдвигами (c целью ускорить алгоритм и сделать порядок сходимости квадратичным) или же без них.[13]
Весьма молодые и не менее актуальные конкуренты QR и QL алгоритмов, применяющиеся для поиска собственных значений:
- Методы divide-and-conquer (разделяй и властвуй), появившиеся в 1980-ых годах [14]
- Relatively robust representation методы, появившиеся в 1990-ых и позволяющие найти собственные числа симметричной матрицы порядка [math]n[/math] за [math]O(n^2)[/math] операций
Если требуется вычислить собственные векторы, то необходимо хранить вычисляемые векторы Ланцоша. Если работа при этом производится только с оперативной памятью, то при большом порядке исходной матрицы (а именно для таких матриц и предназначен метод Ланцоша) число шагов [math]j[/math], которые могут быть выполнены до того момента, как оперативная память будет исчерпана, будет очень незначительно, а следовательно, искомые собственные пары могут не успеть сойтись с требуемой точностью. В этом случае метод Ланцоша можно использовать итерационным образом: после выполнения заданного числа шагов процесс прерывается и, если еще не все требуемые пары Ритца сошлись с требуемой точностью, то формируется новый начальный вектор [math]q_1[/math], являющийся линейной комбинацией векторов Ритца, еще не сошедшихся с заданной точностью, и процесс начинается заново.[15]
1.3 Вычислительное ядро алгоритма
Вычислительное ядро рассматриваемого алгоритма (наиболее ресурсно-затратная часть алгоритма) - формирование на каждом шаге цикла промежуточного вектора [math]z[/math], вычисляемого по формуле: [math]z = A\,q_j[/math]. Данная операция, по сравнению с другими операциями алгоритма, затратна и требовательна, как с точки зрения количества производимых операций, так и с точки зрения объема оперируемых данных.
Например, умножение матрицы размера [math]n\times n[/math] на вектор длины [math]n[/math] требует: [math]n^2+(n-1)n = 2n^2-n[/math] операций умножения и сложения. В свою очередь аналогичная операция умножения матрицы [math](n+1)\times (n+1)[/math] на вектор длины [math](n+1)[/math] требует: [math]2n^2+3n+1[/math] операций умножения и сложения. То есть повышение размерности задачи всего на 1 увеличивает число необходимых действий в этом шаге алгоритма на: [math]4n+1[/math].
Так же, стоит помнить, что, согласно разделу 1.2, данную операцию умножения матрицы на вектор необходимо выполнить [math]k[/math] раз. Нетрудно понять, насколько возрастает и колоссален масштаб операций, если в задачах, где критична точность, размерности [math]n[/math] могут иметь порядок [math]10^5[/math] или даже более.
1.4 Макроструктура алгоритма
Как уже было упомянуто в данной статье в описании алгоритма, рассматриваемый алгоритм состоит из двух последовательно выполненных алгоритмов: метод Ланцоша для построения последовательности подпространств Крылова и ортонормированных векторов Ланцоша и процедура Рэлея-Ритца получения оптимальных приближений собственных значений и соответствующих собственных векторов исходной матрицы.
В первой части алгоритма, где итерационно строятся Крыловское подпространство и трёхдиагональная матрица [math]T_j[/math], можно выделить следующие макрооперации:
- умножение матрицы на вектор (в свою очередь представляет собой умножение вектора на число и сложение векторов);
- вычисление нормы (скалярное произведение векторов + вычисление квадратного корня);
- скалярное произведение векторов;
- сложение векторов и их умножение на вещественные числа
Умножение матрицы на вектор - весьма дешевая и нетривиальная операция, если предполагать, что исходная матрица [math]A[/math] разреженная. Именно она подлежит оптимизации с использованием техник распараллеливания, поскольку она является вычислительным ядром алгоритма, а весь упомянутый процесс построения матрицы [math]T_j[/math] выполняется последовательно.
Рассмотрим вторую часть алгоритма - поиск собственных значений сформированной матрицы [math]T_j[/math].
Далее, наглядно, в виде псевдокода, представлен, упомянутый в разделе 1.2, QR-алгоритм (аналогично можно рассмотреть и QL-алгоритм) со сдвигами Релэя, который весьма популярен на практике.
[math]
\begin{align}
\mathbf{Input}: \;&tridiagonal\;\;matrix \;T\;with\;\;n\times n\;\;size\\
T^{(0)}&:=T\\
\mathbf{for}& \;\;m=n,...,2 \;\; \mathbf{do}\\
&k=0\\
& \mathbf{repeat}\\
& \quad \;\; k=k+1\\
& \quad \;\; \mu^{(k)}=T_{m,m}^{(k-1)}\\
& \quad \;\; Q^{(k)}R^{(k)}=T^{(k-1)}-\mu^{(k)}I\;\;using\;\;QR\;decomposition\\
& \quad \;\; T^{(k)}=R^{(k)}Q^{(k)}+\mu^{(k)}I\\
& \mathbf{until} \;\;\; |T_{m,m-1}^{(k)}| \;is\;\;small\;\;enough\\
& Save \;\;T_{m,m}^{(k)} \;\;as\;\; converged\;\;eigenvalue\;of\;T\\
& Remove \;\boldsymbol{n}\,th\;row\;and\;\boldsymbol{n}\,th\;column\;\;from \;T \\
& and\;take\;this\;new\;cropped\;matrix\;as\;new\;T^{(0)}\;with\;\;(n-1)\times (n-1)\;\;size\\
\mathbf{end}&\; \mathbf{for}
\end{align}
[/math]
Малость наддиагональных и поддиагональных элементов матрицы (фраза "small enough" в псевдокоде) подразумевает:
[math] |T_{m,m-1}^{(k)}| \leq \varepsilon\,|T_{m,m}^{(k)}| \quad\quad [/math] , где [math] \varepsilon [/math] - заданная точность
Также вместо сдвига Релэя, обозначенного в алгоритме через [math]\mu^{(k)}[/math], часто на практике используется сдвиг по Уилкинсону, который даёт гарантированную сходимость внедиагональных элементов матрицы [math] T^{(k)} [/math], формируемой на каждом шаге, к нулю, при этом жертвуя монотонностью их убывания.[16][17]
Подробнее с различными сдвигами и соответствующими оценками скоростей и количествами операций можно ознакомиться по указанной ссылке:[18].
Для совершения QR-декомпозиции на каждом шаге может использоваться любой из алгоритмов по ссылке.[19] Подробные описания этих алгоритмов также доступны на данном ресурсе algowiki-project.
Так как мы оперируем не обычной матрицей и даже не Хессенберговой, а симметричной и трёхдиагональной, то скорость таких алгоритмов значительно возрастёт. Например, согласно данному ресурсу [20], для QL-алгоритма с неявными сдвигами:
Для трёхдиагональной матрицы объем арифметических действий составляет [math] O(n)[/math] на одну итерацию вместо [math] O(n^3)[/math] для матрицы общего вида, а число итераций для нахождения первых собственных значений примерно равно 4 - 5. Но на этих итерациях также уменьшаются внедиагональные элементы правого нижнего угла. И, таким образом, дальнейшие собственные значения ищутся значительно быстрее. Среднее число итераций на каждое собственное значение обычно составляет 1.3 - 1.6.
Аналогично QL, QR-разложение трёхдиагольной матрицы также требует [math] O(n)[/math] флопов[21]
Подводя итог, во второй части алгоритма Ланцоша можно выделить следующие макрооперации:
- умножение матрицы на вещественное число;
- перемножение матриц;
- умножение и сравнение вещественных чисел;
- + набор других макроопераций в зависимости от выбора метода, с помощью которого будет совершаться сама QR или QL-декомпозиция (выше продемонстрированы, уже, как минимум, 3 разных способа).
Так же, важно заметить, что набор макропераций может быть несколько другим, если выбрать какой-либо иной современный метод поиска собственных чисел трёхдиагональной матрицы, не использующий QR и QL разложения(факторизацию). Два таких метода были упомянуты в пункте 1.2.
1.5 Схема реализации последовательного алгоритма
С целью полностью не дублировать раздел 1.2 данной статьи, где представлен наглядный и доступный для понимания псевдокод алгоритма, постараемся лишь коротко просуммировать и обобщить весь перечень последовательных действий в рассматриваемом алгоритме.
В качестве входных данных имеем: вещественная симметричная матрица [math]A[/math] размера [math]n\times n[/math], известный вещественный вектор [math]b[/math] длины [math]n[/math] и число [math]k\lt n[/math].
Далее:
- Инициализируем вещественную константу [math]\beta_0[/math] и векторы [math]q_0[/math] и [math]q_1[/math]
- Итерационно для всех [math]j=1,...,k[/math]:
- Вычисляем вспомогательный вектор [math]z[/math], используя умножение матрицы на вектор
- Вычисляем, используя скалярное произведение векторов, значение [math]\alpha_j[/math] - элемент на главной диагонали трёхдиагональной матрицы [math]T_j[/math]
- Вычисляем по формуле новое значение и перезаписываем вектор [math]z[/math]
- Вычисляем значение [math]\beta_j[/math] - элементы непосредственно над и под главной диагональю той же матрицы [math]T_j[/math]
- Вычисляем, зная вектор [math]z[/math], очередной столбец матрицы [math]Q[/math], он же вектор Ланцоша : [math]\,\,q_{j+1}[/math]
- Теперь, когда матрица [math]T_j[/math] сформирована на очередном шаге, находим её собственные значения и вектора любым доступным способом, о чём было подробно сказано в пункте 1.2
- Переходим на следующую итерацию: [math]j[/math]++
1.6 Последовательная сложность алгоритма
Оценим количество операций и сложность последовательного алгоритма, изложенного в предыдущем разделе.
- Для вычисления вектора [math]z[/math] умножается матрица размера [math]n\times n[/math] на вектор длины [math]n[/math], и потребуется [math]n^2[/math] операций умножения и [math]n^2[/math] операций сложения.
- Умножение векторов [math]q^T_j[/math] и [math]z[/math] длины [math]n[/math] потребует [math]n[/math] операций умножения и [math]n[/math] операций сложения.
- При вычислении нового значения вектора [math]z[/math] поэлементное сложение двух векторов длины [math]n[/math] требует [math]n[/math] операций сложения.
- Умножение вектора длины [math]n[/math] на вещественное число требует [math]n[/math] операций умножения.
- Нахождение квадратичной нормы вектора [math]z[/math] длины [math]n[/math] требует [math]n[/math] умножений и [math]n[/math] сложений и ещё 1 операцию извлечения квадратного корня.
- Заключительное нахождение собственных значений и собственных векторов трёхдиагональной матрицы [math]T_j[/math] размера [math]j\times j[/math] с помощью QR-алгоритма потребует в худшем случае [math]O(j^3)[/math] операций.[22]
Посчитаем теперь суммарное количество простейших операций на одной итерации алгоритма (без учёта записей в память):
- [math]n^2+5\,n[/math] операций умножения/деления
- [math]n^2+4\,n[/math] операций сложения/вычитания
- 1 операция извлечения квадратного корня
Отдельно после всех итераций при [math]j=k[/math] :
- [math]O(k^3)[/math] операций для поиска собственных значений и собственных векторов трёхдиагональной матрицы [math]T_k[/math]
Итого можно утверждать следующее:
Последовательная сложность одной итерации рассматриваемого алгоритма: [math]O(n ^ 2) [/math]
Суммарная сложность алгоритма ([math]k[/math] итераций): [math]O(k\,n ^ 2) + O(k ^ 3)[/math] [23]
На практике же обычно рассматривается число [math]k\lt \lt n[/math], поэтому второе слагаемое можно опустить.
1.7 Информационный граф
На рис. 1 продемонстрирован граф одной итерации (при каком-либо произвольном значении итератора [math]j[/math]) описанного алгоритма без отображения входных и выходных данных. Наглядно продемонстрированы связи между всеми действиями, и с помощью деления на [math]n[/math] потоков показано, какие операции возможно выполнять параллельно на каждом шаге с целью оптимизации и экономии машинного времени. В результате, после параллельно выполненных операций Division на заключительном ярусе, на выходе имеем значение следующего вектора Ланцоша [math]q_{j+1}[/math], после чего следует переход на следующую итерацию, и процесс повторяется.
Обозначения на рисунке:
Simp (от англ. simple) - операции сложения и умножения вещественных чисел при вычислении произведения матрицы на вектор;
Vec mult (от англ. vectors multiplication) - операция скалярного умножения двух векторов;
Vec subtr (от англ. vectors subtraction, из-за использованных в операции вычитаний векторов) - операция умножения вектора на число (выполняется дважды) и формирование нового значения [math]z_{new}[/math] по формуле: [math]z_{new} = z - \alpha_j q_j - \beta_{j-1}q_{j-1} \;[/math];
[math]||\cdot||[/math] - операция вычисления нормы вектора;
Division - операция деления вектора на вещественное число [math]\beta_j[/math]
Важно отметить, что упомянутые выше операции также легко поддаются оптимизации. Например, попарные умножения вещественных координат векторов при вычислении скалярного произведения также легко выполняются параллельно на [math]n[/math] потоках, а затем можно применить суммирование методом сдваивания, о котором сказано в следующем разделе. Умножение или деление вектора на вещественное число являющееся, по определению, умножением или делением всех его координат на это число тоже может быть выполнено эффективнее, если мы используем [math]n[/math] потоков, а не выполняем эти действия последовательно.
1.8 Ресурс параллелизма алгоритма
Параллельные операции возможны только внутри итераций, так как рассматриваемый алгоритм является итерационным, и сами итерации строго последовательны.
Рассмотрим в этом разделе подробнее, какой выигрыш мы можем получить при распараллеливании операций внутри одной итерации согласно графу из предыдущего раздела.
Умножение вещественной симметричной матрицы [math]A[/math] размера [math]n\times n[/math] на вектор [math]b[/math] длины [math]n[/math] требует последовательного выполнения [math]n[/math] ярусов умножений и сложений. Сложение элементов вектора длины [math]n[/math] на каждом шаге перемножения можно оптимизировать и выполнить за [math]\log_2 n[/math] действий, если применять метод сдваивания.
Дальнейшие операции выполняются последовательно, а вычисление значений векторов происходит за один ярус операций сложения или умножения.
Ресурс параллелизма алгоритма вычисления собственных значений построенной трёхдиагональной матрицы [math]T_k[/math] размера [math]k\times k[/math] зависит от выбранного алгоритма (об этих алгоритмах подробнее было сказано в разделах 1.2 и 1.4). Будет очень затратно с точки зрения объёма материала пытаться рассмотреть пусть даже часть этих методов в этой статье, а так же тонкости их распараллеливания. Предлагаем читателям при желании самим ознакомиться с этими алгоритмами на данном ресурсе или прибегнув к иным источникам.
При классификации по высоте ЯПФ, таким образом, алгоритм Ланцоша без переортогонализации относится к алгоритмам с логарифмической сложностью, и его сложность равна [math]O(\log_2 n)[/math] с важным замечанием, что это сложность только одной итерации, а максимум в алгоритме может быть выполнено последовательно [math]k[/math] таких однотипных итераций, если не будет осуществлён ранний выход из цикла.
Несмотря на то, что на графе в предыдущем разделе для лучшей визуализации и понимания было изображено [math]n[/math] потоков (никаких допущений мы не делали и нарушений с точки зрения логики и математики нет, можно изобразить большее число потоков, просто часть времени некоторые из них могут бездействовать и не использоваться), на самом деле правильным и разумным будет реализовать начальное параллельное выполнение [math]n^2[/math] операций умножения всех вещественных элементов матрицы [math]A[/math] на соответствующие элементы вектора [math]q_j[/math], после чего применять тот же самый упомянутый метод сдваивания.
Поэтому при классификации по ширине ЯПФ его сложность будет квадратичной и равна [math]O(n^2)[/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]\ \frac{n^2-n}{2}+n+n+1 =\frac{n^2+3n}{2} + 1[/math]
Выходные данные алгоритма: вектор собственных значений [math]\Theta^k[/math] длины [math]k[/math], матрица [math]S^k[/math] из соответствующих собственных векторов размера [math]n\times k[/math].
Объём выходных данных: [math]k\;(n + 1)[/math].
1.10 Свойства алгоритма
В данном разделе перечислены без какой-либо хронологии или связи друг с другом наиболее важные и разнообразные свойства алгоритма, на которые стоит и полезно обратить внимание, а также которые выгодно отличают его от схожих алгоритмов, решающих ту же задачу.
1) Отношение последовательной сложности алгоритма к параллельной,с учётом [math]k[/math] итераций, равно [math]\;\;\frac{kn^2}{k \log_2{n}}=\frac{n^2}{\log_2{n}}[/math];
2) Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных, равна [math]\;\;\frac{k\,n^2}{0.5\,n^2+1.5\,n+k\,n+k+1}[/math] и [math]\approx 2\,k[/math], так как на практике верно отношение [math]k\lt \lt n[/math] ;
3) Для собственных значений формируемых матриц [math]T_j[/math] верно отношение (следствие теоремы Коши о перемежаемости): [math]\lambda_i(T_{k+1})\geq \lambda_i(T_{k})\geq \lambda_{i+1}(T_{k+1})\geq \lambda_{i+1}(T_{k})[/math] ;[24]
4) Крайние (наибольшие и наименьшие) собственные значения матриц [math]T_j[/math] сходятся к крайним собственным значениям матрицы [math]A[/math] первыми (это часто происходит уже на ранних шагах при [math]j\approx 2\,\sqrt{n}[/math][25]), а собственные значения в середине спектра - последними;
5) Из-за ограниченной точности постепенно теряется ортогональность вектора Ланцоша [math]q_j[/math] к предыдущим векторам Ланцоша, поэтому необходимо примерно каждые 10-15 итераций проводить дорогостоящую операцию реортогонализации, но это уже будет иной алгоритм с очень малым различием в одной операции и в программном коде, реализующем его, соответственно; [26]
6) Эффективность и быстрота выполнения алгоритма очень сильно зависит от скорости памяти (диска). Согласно тесту только 6% времени работы программы приходится на вычисления, остальное время затрачивается на ожидание отклика диска;[27]
7) Метод Ланцоша удобен тем, что не требует хранения исходной матрицы полным массивом: метод использует исходную матрицу только в операциях умножения матрицы на вектор, что позволяет эффективно использовать разреженность матрицы или регулярность структуры матрицы. Поэтому метод Ланцоша может быть использован для матриц таких больших порядков, когда методы вращений и отражений не могут быть применены.
2 Программная реализация алгоритма
2.1 Особенности реализации последовательного алгоритма
2.2 Локальность данных и вычислений
2.3 Возможные способы и особенности параллельной реализации алгоритма
2.4 Масштабируемость алгоритма и его реализации
Для исследования масштабируемости рассматриваемого алгоритма Ланцоша без переортогонализации автором была реализована программа на языке С++ с использованием технологии MPI. [28] Дальнейшее исследование было проведено на суперкомпьютере "Ломоносов" Суперкомпьютерного комплекса МГУ.[29]
Важно отметить, что реализованная программа выполняет только первую часть алгоритма - формирование трёхдиагональной матрицы [math]T_j[/math]. Вторая часть алгоритма (задача поиска собственных значений матрицы [math]T_j[/math]) может быть решена несколькими методами, каждый из которых обладает своей эффективностью распараллеливания и характерными свойствами. Подробно этот вопрос уже обсуждался в статье ранее, поэтому не будем ещё раз заострять на этом внимание и останавливаться.
Сборка осуществлялась со следующими параметрами:
- Компилятор intel/15.0.090
- Openmpi/1.8.4-icc
В серии проведённых расчётов рассматривались следующие числовые значения параметров:
- Размер [math]n[/math] задачи и, соответственно, матрицы [math]A[/math], задействованной в операции умножения на вектор: [2000 : 30000] с шагом 1000
- Число [math]p[/math] процессоров: 1, 2, 4, 16, 32, 48, 64, 96, 128, 192, 256
- Число итераций в алгоритме: [math]k=350[/math]
Число [math]k[/math] взято таким вопреки информации в начале статьи, где говорится, что значение [math]k[/math] редко превышает [math]10^2[/math] (хоть мы и имеем право брать его любым по нашему усмотрению). Это сделано исключительно для лучшей визуализации пиков на графиках в данном разделе и наглядности получаемых результатов, так как при меньших на порядок значениях параметра [math]k[/math] времена выполнения программ были слишком малы даже при минимальных числах процессоров и максимальных размерах [math]n[/math] задачи.
На рис. 2 изображён график зависимости времени выполнения программы от числа процессоров и размера [math]n[/math] задачи.
Многочисленные тесты показали при малых количествах ядер уменьшение времени выполнения программы почти в 2 раза при увеличении числа ядер в 2 раза на всём диапазоне размеров матриц, что и отражает сильный излом на первом графике. Изменение значений времени можно легко оценить по предоставленной цветовой шкале. Был построен график эффективности распараллеливания (parallel efficiency)[30] в зависимости от числа процессоров и размера задачи, изображённый на рис. 3. Получены следующие результаты численных экспериментов:
- Средняя эффективность распараллеливания программы составила: 42.5576% ;
- Минимальная эффективность реализации: 0.674% (число процессоров 256 и минимальный размер матрицы 2000);
- Максимальная эффективность реализации: 77.773% (число процессоров 2, размер матрицы 20000).
Нужно понимать, что это лишь экстремумы, соответствующие двум экспериментам, которые сами по себе не дают полной картины и не позволяют однозначно судить о параллельных качествах алгоритма и реализующей его программы при столь большом числе параметров и проводимых расчётов.
На основании рис. 3 можно отметить следующие значимые и важные факты:
- Имеется ярко выраженный спад эффективности при минимальном рассматриваемом размере матрицы [math]n=2000[/math] вдоль всей оси OY, отвечающей за число процессоров;
- Присутствуют два пика эффективности (жёлтого цвета на рис. 3): при числе [math]p[/math] процессоров 2 и 128. Затем при дальнейшем увеличении числа процессоров с 128 до 256 наблюдается постепенное уменьшение эффективности реализации. Это связано с увеличением накладных расходов и затрат времени на обмены сообщениями между процессами.
2.5 Динамические характеристики и эффективность реализации алгоритма
2.6 Выводы для классов архитектур
2.7 Существующие реализации алгоритма
Несмотря на то, что алгоритм является далеко не самым популярным, алгоритмом, про который нельзя сказать, что он всегда «на слуху», на сегодняшний день существует множество реализаций на различных популярных языках.
Перечислим далее некоторые из них, указывая язык программирования, лежащий в их основе, и некоторые важные характеристики, которые обсуждались в статье ранее:
- Code on netlib.org by Jane Cullum and Ralph Willoughby (Fortran 77; без реортогонализации векторов; без реализации распараллеливания)[31]
- Lanczos algorithm on freesourcecode.net (Matlab; присутствует реортогонализация векторов; без реализации распараллеливания)[32]
- Lanczos for eigenvalues in Numerical Linear Algebra, Spring 2007 (Matlab; частичная или полная реортогонализация - доступны оба варианта; без реализации распараллеливания)[33]
- Planso (название происходит от parallel Lanso.f) code by Kesheng Wu and Horst D. Simon (Fortran 77; частичная реортогонализация векторов; использование MPI для коммуникаций)[34]
- Lanczos.cpp in the Vienna Computing Library (C++, частичная реортогонализация, без реализации распараллеливания) [35]
- Parallel Eigen Values code using C++ AMP on microsoft msdn blog (C++; ? ; распараллеливание есть и реализовано через C++ AMP) [36]
3 Литература
- ↑ Парлетт Б. - Симметричная проблема собственных значений. Численные методы //М.: Мир. - 1983. (c. 276)
- ↑ Susan W. Bostic - Lanczos Eigensolution Method for High-Perfomance Computers, page 7
- ↑ James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 381)
- ↑ James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 313, [math] \S [/math] 6.6 Методы Крыловского подпространства)
- ↑ James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 381)
- ↑ James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 315)
- ↑ Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 429)
- ↑ Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 ([math]\S[/math] 8.4)
- ↑ Парлетт Б. Симметричная проблема собственных значений. Численные методы.,: Мир, 1983. с. 179-182
- ↑ https://en.wikipedia.org/wiki/Tridiagonal_matrix#Eigenvalues Раздел eigenvalues
- ↑ Уилкинсон Дж. X. Алгебраическая проблема собственныx значений. Изд-во "Наука", 1970. - глава 5, с. 272-278
- ↑ Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 394-395)
- ↑ http://algorithm.narod.ru/ln/eigen/ETridiag.html
- ↑ https://goo.gl/dapvbn ссылку пришлось сократить с помощью Google url shortener, так как символы подчеркивания портили её и не давали перейти по 1 клику
- ↑ http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.5)
- ↑ Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 378, вторая половина страницы)
- ↑ Парлетт Б. Симметричная проблема собственных значений. Численные методы.,: Мир, 1983. с. 169
- ↑ Парлетт Б. Симметричная проблема собственных значений. Численные методы.,: Мир, 1983. с. 179-182
- ↑ https://en.wikipedia.org/wiki/QR_decomposition
- ↑ http://algorithm.narod.ru/ln/eigen/ETridiag.html
- ↑ Голуб Дж., Ван Лоун Ч. - Матричные вычисления//М.: Мир. - 1999 (c. 378, начало раздела 8.2.2)
- ↑ http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.2, "Скорость сходимости при этом всегда не хуже квадратичной и почти всегда лучше кубической.")
- ↑ Здесь мы полагаем, что мы не вычисляем собственные значения и векторы матрицы [math]T_j[/math] на каждом промежуточном шаге, а лишь единожды затрачиваем [math]O(k ^ 3)[/math] действий в конце для нахождения [math]k[/math] собственных значений и векторов матрицы [math]T_k[/math]
- ↑ James W. Demmel - Вычислительная линейная алгебра. Теория и приложения //Мир. - 2001 (c. 383)
- ↑ http://num-anal.srcc.msu.ru/lib_na/int_ae/int_ae6.htm (пункт 6.5)
- ↑ Sam Handler - The Lanczos Algorithm For Large-Scale Eigenvalue Problems (08.01.07), slide №8
- ↑ Sam Handler - The Lanczos Algorithm For Large-Scale Eigenvalue Problems (08.01.07), slide №10
- ↑ https://goo.gl/pNOFmW или альтернативная ссылка с прикреплённым кодом: https://goo.gl/9AapM6 , по просьбе на почту я (автор статьи) готов предоставить желающим доступ к проекту с этим кодом на ресурсе Bitbucket
- ↑ https://parallel.ru/cluster/lomonosov.html
- ↑ https://goo.gl/WCNEjR
- ↑ http://www.netlib.org/lanczos/leval
- ↑ http://freesourcecode.net/matlabprojects/61741/lanczos-algorithm--in-matlab
- ↑ Ссылки на файлы lanso.m и lanfu.m можно найти на https://www.nada.kth.se/~ruhe/2D5219/labs2007.html
- ↑ https://github.com/jiahao/planso.jl/tree/master/external/PLAN/plan К сожалению, ссылка в описании пакета на github, ведущая на сайт National Energy Research Scientific Computing Center (NERSC), с более подробной информацией о данной программе больше не активна и выдаёт результат Page not found
- ↑ http://viennacl.sourceforge.net/doc/lanczos_8cpp_source.html
- ↑ https://blogs.msdn.microsoft.com/nativeconcurrency/2013/12/20/eigen-values/ Подробнее о C++ Accelerated Massive Parallelism можно почитать здесь: https://msdn.microsoft.com/ru-ru/library/hh265137(v=vs.140).aspx или здесь: http://professorweb.ru/my/csharp/optimization/level4/4_6.php