<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=GrishinaAnna</id>
	<title>AlgowikiPool - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=GrishinaAnna"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/pool/Special:Contributions/GrishinaAnna"/>
	<updated>2026-10-23T06:30:48Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:Assignments/Awaiting&amp;diff=803</id>
		<title>Категория:Assignments/Awaiting</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:Assignments/Awaiting&amp;diff=803"/>
		<updated>2016-10-15T17:35:34Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;https://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:Assignments/Awaiting&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;https://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:Assignments/Awaiting&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=799</id>
		<title>Template:Assignment</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=799"/>
		<updated>2016-10-15T17:18:04Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Плашка&lt;br /&gt;
  |bgcolor     =F0FFFF &lt;br /&gt;
  |bordercolor =006e27&lt;br /&gt;
  |img={{#if: {{{1|}}} | 180px-Symbol_wait.svg.png | 180px-Symbol_wait.svg.png }}&lt;br /&gt;
  |title=&amp;lt;span style=&amp;quot;font-size:16px&amp;quot;&amp;gt;{{#if: {{{1|}}} | Эта работа успешно выполнена&amp;lt;br /&amp;gt;Преподавателю: [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:Готово}}}} в основное пространство], [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|Алговики:Студенческие работы/{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:На доработку}}}} в подстраницу] | Эта работа ждет рассмотрения преподавателем&amp;lt;br /&amp;gt;&#039;&#039;Дата последней правки страницы:&#039;&#039; &#039;&#039;&#039;{{#time: d.m.Y |{{REVISIONTIMESTAMP}}}}&#039;&#039;&#039;}}&amp;lt;/span&amp;gt;&lt;br /&gt;
  |text={{#if: {{{1|}}} | Данное задание было проверено и зачтено.&amp;lt;br /&amp;gt;Проверено [[User:{{{1}}}|{{{1}}}]]. | Авторы этой статьи считают, что задание выполнено.}}&lt;br /&gt;
  |cat={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done/{{{1}}}&amp;lt;/includeonly&amp;gt; | &amp;lt;includeonly&amp;gt;Assignments/Awaiting&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
  |cat2={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=798</id>
		<title>Template:Assignment</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=798"/>
		<updated>2016-10-15T17:17:53Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Плашка&lt;br /&gt;
  |bgcolor     =F0FFFF &lt;br /&gt;
  |bordercolor =006e27&lt;br /&gt;
  |img={{#if: {{{1|}}} | Symbol_confirmed.svg | 180px-Symbol_wait.svg.png }}&lt;br /&gt;
  |title=&amp;lt;span style=&amp;quot;font-size:16px&amp;quot;&amp;gt;{{#if: {{{1|}}} | Эта работа успешно выполнена&amp;lt;br /&amp;gt;Преподавателю: [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:Готово}}}} в основное пространство], [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|Алговики:Студенческие работы/{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:На доработку}}}} в подстраницу] | Эта работа ждет рассмотрения преподавателем&amp;lt;br /&amp;gt;&#039;&#039;Дата последней правки страницы:&#039;&#039; &#039;&#039;&#039;{{#time: d.m.Y |{{REVISIONTIMESTAMP}}}}&#039;&#039;&#039;}}&amp;lt;/span&amp;gt;&lt;br /&gt;
  |text={{#if: {{{1|}}} | Данное задание было проверено и зачтено.&amp;lt;br /&amp;gt;Проверено [[User:{{{1}}}|{{{1}}}]]. | Авторы этой статьи считают, что задание выполнено.}}&lt;br /&gt;
  |cat={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done/{{{1}}}&amp;lt;/includeonly&amp;gt; | &amp;lt;includeonly&amp;gt;Assignments/Awaiting&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
  |cat2={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=File:180px-Symbol_wait.svg.png&amp;diff=797</id>
		<title>File:180px-Symbol wait.svg.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=File:180px-Symbol_wait.svg.png&amp;diff=797"/>
		<updated>2016-10-15T17:17:20Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=795</id>
		<title>Template:Assignment</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=795"/>
		<updated>2016-10-15T17:16:23Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Плашка&lt;br /&gt;
  |bgcolor     =F0FFFF &lt;br /&gt;
  |bordercolor =006e27&lt;br /&gt;
  |img={{#if: {{{1|}}} | Symbol_confirmed.svg | Symbol_wait.svg }}&lt;br /&gt;
  |title=&amp;lt;span style=&amp;quot;font-size:16px&amp;quot;&amp;gt;{{#if: {{{1|}}} | Эта работа успешно выполнена&amp;lt;br /&amp;gt;Преподавателю: [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:Готово}}}} в основное пространство], [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|Алговики:Студенческие работы/{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:На доработку}}}} в подстраницу] | Эта работа ждет рассмотрения преподавателем&amp;lt;br /&amp;gt;&#039;&#039;Дата последней правки страницы:&#039;&#039; &#039;&#039;&#039;{{#time: d.m.Y |{{REVISIONTIMESTAMP}}}}&#039;&#039;&#039;}}&amp;lt;/span&amp;gt;&lt;br /&gt;
  |text={{#if: {{{1|}}} | Данное задание было проверено и зачтено.&amp;lt;br /&amp;gt;Проверено [[User:{{{1}}}|{{{1}}}]]. | Авторы этой статьи считают, что задание выполнено.}}&lt;br /&gt;
  |cat={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done/{{{1}}}&amp;lt;/includeonly&amp;gt; | &amp;lt;includeonly&amp;gt;Assignments/Awaiting&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
  |cat2={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=794</id>
		<title>Template:Assignment</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=794"/>
		<updated>2016-10-15T17:15:31Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Плашка&lt;br /&gt;
  |bgcolor     =F0FFFF &lt;br /&gt;
  |bordercolor =006e27}}&lt;br /&gt;
  |title=&amp;lt;span style=&amp;quot;font-size:16px&amp;quot;&amp;gt;{{#if: {{{1|}}} | Эта работа успешно выполнена&amp;lt;br /&amp;gt;Преподавателю: [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:Готово}}}} в основное пространство], [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|Алговики:Студенческие работы/{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:На доработку}}}} в подстраницу] | Эта работа ждет рассмотрения преподавателем&amp;lt;br /&amp;gt;&#039;&#039;Дата последней правки страницы:&#039;&#039; &#039;&#039;&#039;{{#time: d.m.Y |{{REVISIONTIMESTAMP}}}}&#039;&#039;&#039;}}&amp;lt;/span&amp;gt;&lt;br /&gt;
  |text={{#if: {{{1|}}} | Данное задание было проверено и зачтено.&amp;lt;br /&amp;gt;Проверено [[User:{{{1}}}|{{{1}}}]]. | Авторы этой статьи считают, что задание выполнено.}}&lt;br /&gt;
  |cat={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done/{{{1}}}&amp;lt;/includeonly&amp;gt; | &amp;lt;includeonly&amp;gt;Assignments/Awaiting&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
  |cat2={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=791</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=791"/>
		<updated>2016-10-15T17:11:03Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=788</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=788"/>
		<updated>2016-10-15T17:07:34Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;[[Категория:Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=787</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=787"/>
		<updated>2016-10-15T17:06:57Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:%D0%9F%D0%BB%D0%B0%D1%88%D0%BA%D0%B0&amp;diff=785</id>
		<title>Template:Плашка</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:%D0%9F%D0%BB%D0%B0%D1%88%D0%BA%D0%B0&amp;diff=785"/>
		<updated>2016-10-15T17:06:17Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;&amp;lt;table style=&amp;quot;clear: both; width: {{{width|80%}}}; background-color: #{{{bgcolor|fefefe}}}; border-color:#{{{outerbordercolor|{{{bordercolor|AAB}}}}}} #{{{outerbordercolor|{{{...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;table style=&amp;quot;clear: both; width: {{{width|80%}}}; background-color: #{{{bgcolor|fefefe}}}; border-color:#{{{outerbordercolor|{{{bordercolor|AAB}}}}}} #{{{outerbordercolor|{{{bordercolor|AAB}}}}}} #{{{outerbordercolor|{{{bordercolor|AAB}}}}}} #{{{bordercolor|999}}}; border-style: solid; border-width: 1px 1px 1px 10px; padding: 4px; margin: 1px auto; vertical-align: middle; text-align: left;&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;{{#expr: {{{imgwidth|64}}}+8 }}px&amp;quot; height=&amp;quot;{{{height|auto}}}&amp;quot;&amp;gt;[[Файл:{{{img|3d nonzero components.svg}}}|{{{imgwidth|64}}}px]]&amp;lt;/td&amp;gt;&amp;lt;td style=&amp;quot;vertical-align: middle&amp;quot;&amp;gt;&amp;lt;!-- &lt;br /&gt;
 --&amp;gt;{{#if: {{{title|}}} | &#039;&#039;&#039;{{{title}}}&#039;&#039;&#039;&amp;lt;br /&amp;gt;}}&amp;lt;!-- &lt;br /&gt;
 --&amp;gt;{{{text|Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In est libero, tristique vel, vestibulum a, aliquam sit amet, nisl. Curabitur suscipit euismod sapien. Nullam ligula.}}}&amp;lt;!-- &lt;br /&gt;
 --&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;includeonly&amp;gt;{{#if: {{{cat|}}} | [[Категория:{{{cat}}}]] }}{{#if: {{{cat2|}}} | [[Категория:{{{cat2}}}]] }}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
== Описание ==&lt;br /&gt;
Параметры:&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; — заголовок (по умолчанию: без заголовка)&lt;br /&gt;
* &#039;&#039;&#039;text&#039;&#039;&#039; — текст (по умолчанию: lorem ipsum)&lt;br /&gt;
* &#039;&#039;&#039;bgcolor&#039;&#039;&#039; — фоновый цвет в формате RGB без знака # (по умолчанию: fefefe)&lt;br /&gt;
* &#039;&#039;&#039;bordercolor&#039;&#039;&#039; — цвет бордюра (для гармонии с картинкой и фоном; по умолчанию: 999)&lt;br /&gt;
* &#039;&#039;&#039;outerbordercolor&#039;&#039;&#039; — цвет верхнего, правого и нижнего бордеров (по умолчанию: AAB или bordercolor, если он задан)&lt;br /&gt;
* &#039;&#039;&#039;img&#039;&#039;&#039; — картинка без префикса «Файл:» (по умолчанию: 3d_nonzero_components.svg)&lt;br /&gt;
* &#039;&#039;&#039;imgwidth&#039;&#039;&#039; — для нестандартных картинок. Желательно не трогать (по умолчанию: 64)&lt;br /&gt;
* &#039;&#039;&#039;cat&#039;&#039;&#039; — категория без префикса «Категория:» (по умолчанию: none)&lt;br /&gt;
* &#039;&#039;&#039;cat2&#039;&#039;&#039; — вторая категория без префикса «Категория:» (по умолчанию: none)&lt;br /&gt;
* &#039;&#039;&#039;height&#039;&#039;&#039; — высота плашки (по умолчанию: auto)&lt;br /&gt;
* &#039;&#039;&#039;width&#039;&#039;&#039; — ширина плашки (по умолчанию: 80%)&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=782</id>
		<title>Template:Assignment</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Assignment&amp;diff=782"/>
		<updated>2016-10-15T17:03:29Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;{{Плашка   |bgcolor     =F0FFFF    |bordercolor =006e27   |img={{#if: {{{1|}}} | Symbol_confirmed.svg | Symbol_wait.svg }}   |title=&amp;lt;span style=&amp;quot;font-size:16px&amp;quot;&amp;gt;{{#if: {...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Плашка&lt;br /&gt;
  |bgcolor     =F0FFFF &lt;br /&gt;
  |bordercolor =006e27&lt;br /&gt;
  |img={{#if: {{{1|}}} | Symbol_confirmed.svg | Symbol_wait.svg }}&lt;br /&gt;
  |title=&amp;lt;span style=&amp;quot;font-size:16px&amp;quot;&amp;gt;{{#if: {{{1|}}} | Эта работа успешно выполнена&amp;lt;br /&amp;gt;Преподавателю: [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:Готово}}}} в основное пространство], [{{fullurl:Служебная:Movepage/{{FULLPAGENAME}}|wpNewTitle={{urlencode:{{{rename|Алговики:Студенческие работы/{{SUBPAGENAME}}}}}}}&amp;amp;wpReason={{urlencode:На доработку}}}} в подстраницу] | Эта работа ждет рассмотрения преподавателем&amp;lt;br /&amp;gt;&#039;&#039;Дата последней правки страницы:&#039;&#039; &#039;&#039;&#039;{{#time: d.m.Y |{{REVISIONTIMESTAMP}}}}&#039;&#039;&#039;}}&amp;lt;/span&amp;gt;&lt;br /&gt;
  |text={{#if: {{{1|}}} | Данное задание было проверено и зачтено.&amp;lt;br /&amp;gt;Проверено [[User:{{{1}}}|{{{1}}}]]. | Авторы этой статьи считают, что задание выполнено.}}&lt;br /&gt;
  |cat={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done/{{{1}}}&amp;lt;/includeonly&amp;gt; | &amp;lt;includeonly&amp;gt;Assignments/Awaiting&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
  |cat2={{#if: {{{1|}}} | &amp;lt;includeonly&amp;gt;Assignments/Done&amp;lt;/includeonly&amp;gt;}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=781</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=781"/>
		<updated>2016-10-15T17:02:58Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=779</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=779"/>
		<updated>2016-10-15T16:41:57Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=778</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=778"/>
		<updated>2016-10-15T16:41:09Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=777</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=777"/>
		<updated>2016-10-15T16:40:05Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=775</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=775"/>
		<updated>2016-10-15T16:28:42Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[[en:Метод Якоби вычисления сингулярных чисел и векторов]]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=774</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=774"/>
		<updated>2016-10-15T16:28:09Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[[en:Метод Якоби вычисления сингулярных чисел и векторов]]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=769</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=769"/>
		<updated>2016-10-15T16:20:21Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=709</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=709"/>
		<updated>2016-10-15T09:41:10Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=708</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=708"/>
		<updated>2016-10-15T09:38:51Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;[[Категория:Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=707</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=707"/>
		<updated>2016-10-15T09:38:15Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;[[Категория:Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=704</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=704"/>
		<updated>2016-10-15T09:03:01Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм) &amp;lt;ref&amp;gt;Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[#Макроструктура алгоритма|&#039;&#039;Макроструктура алгоритма&#039;&#039;]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=701</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=701"/>
		<updated>2016-10-15T08:59:24Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 (https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf)&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках &amp;lt;ref&amp;gt;JacobiSVD Class Template Reference, https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Parallelism in the Intel® Math Kernel Library, https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Singular Value Decomposition - LAPACK Driver Routines, https://software.intel.com/en-us/node/521149&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. Erricos John, Handbook on Parallel Computing and Statistics, p. 126 [https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf]&lt;br /&gt;
&lt;br /&gt;
4. Singular Value Decomposition - LAPACK Driver Routines [https://software.intel.com/en-us/node/521149]&lt;br /&gt;
&lt;br /&gt;
5. Parallelism in the Intel® Math Kernel Library [https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library]&lt;br /&gt;
&lt;br /&gt;
6. JacobiSVD Class Template Reference [https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=699</id>
		<title>Template:Algorithm</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=699"/>
		<updated>2016-10-15T08:57:09Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{level-a}}&lt;br /&gt;
{{infobox&lt;br /&gt;
| style-options=max-width: 40%&lt;br /&gt;
| title={{{name|}}}&lt;br /&gt;
| title-1={{#if: {{{serial_complexity|}}}{{{input_data|}}}{{{output_data|}}} | Последовательный алгоритм}}&lt;br /&gt;
| label-1.1=Последовательная сложность&lt;br /&gt;
| data-1.1={{{serial_complexity|}}}&lt;br /&gt;
| label-1.2=Объём входных данных&lt;br /&gt;
| data-1.2={{{input_data|}}}&lt;br /&gt;
| label-1.3=Объём выходных данных&lt;br /&gt;
| data-1.3={{{output_data|}}}&lt;br /&gt;
| title-2={{#if: {{{parallel_complexity|}}}{{{pf_height|}}}{{{pf_width|}}} | Параллельный алгоритм}}&lt;br /&gt;
| label-2.1=Параллельная сложность&lt;br /&gt;
| data-2.1={{{parallel_complexity|}}}&lt;br /&gt;
| label-2.2=Высота ярусно-параллельной формы&lt;br /&gt;
| data-2.2={{{pf_height|}}}&lt;br /&gt;
| label-2.3=Ширина ярусно-параллельной формы&lt;br /&gt;
| data-2.3={{{pf_width|}}}&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;source lang=html4strict&amp;gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Разложение Холецкого&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en:Template:Algorithm]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=697</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=697"/>
		<updated>2016-10-15T08:55:32Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&amp;lt;ref&amp;gt;Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий.&amp;lt;ref&amp;gt;Erricos John, Handbook on Parallel Computing and Statistics, p. 126 |url=https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf&amp;lt;/ref&amp;gt; Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)).&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. Erricos John, Handbook on Parallel Computing and Statistics, p. 126 [https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf]&lt;br /&gt;
&lt;br /&gt;
4. Singular Value Decomposition - LAPACK Driver Routines [https://software.intel.com/en-us/node/521149]&lt;br /&gt;
&lt;br /&gt;
5. Parallelism in the Intel® Math Kernel Library [https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library]&lt;br /&gt;
&lt;br /&gt;
6. JacobiSVD Class Template Reference [https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=En:Template:Level-a&amp;diff=694</id>
		<title>En:Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=En:Template:Level-a&amp;diff=694"/>
		<updated>2016-10-15T08:52:40Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=693</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=693"/>
		<updated>2016-10-15T08:52:01Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;[[Категория:Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=690</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=690"/>
		<updated>2016-10-15T08:50:37Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)) &amp;lt;ref&amp;gt;{{Cite book|title = Handbook on Parallel Computing and Statistics, p.126 |last = Erricos|first = John |url=https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf}}&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;Дж. Деммель, Вычислительная линейная алгебра, с.263&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. Erricos John, Handbook on Parallel Computing and Statistics, p. 126 [https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf]&lt;br /&gt;
&lt;br /&gt;
4. Singular Value Decomposition - LAPACK Driver Routines [https://software.intel.com/en-us/node/521149]&lt;br /&gt;
&lt;br /&gt;
5. Parallelism in the Intel® Math Kernel Library [https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library]&lt;br /&gt;
&lt;br /&gt;
6. JacobiSVD Class Template Reference [https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=688</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=688"/>
		<updated>2016-10-15T08:42:44Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=En:Template:Level-a&amp;diff=687</id>
		<title>En:Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=En:Template:Level-a&amp;diff=687"/>
		<updated>2016-10-15T08:41:49Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;Уровень алгоритма&amp;lt;/indic...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;[[Категория:Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=686</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=686"/>
		<updated>2016-10-15T08:40:16Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)) &amp;lt;ref&amp;gt;{{Cite book|title = Handbook on Parallel Computing and Statistics, p.126 |last = Erricos|first = John |url=https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf}}&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;{{Cite book|title =  Вычислительная линейная алгебра, p.263 |last = Деммель|first = Дж.}}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. Erricos John, Handbook on Parallel Computing and Statistics, p. 126 [https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf]&lt;br /&gt;
&lt;br /&gt;
4. Singular Value Decomposition - LAPACK Driver Routines [https://software.intel.com/en-us/node/521149]&lt;br /&gt;
&lt;br /&gt;
5. Parallelism in the Intel® Math Kernel Library [https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library]&lt;br /&gt;
&lt;br /&gt;
6. JacobiSVD Class Template Reference [https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=685</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=685"/>
		<updated>2016-10-15T08:39:33Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a|Метод Якоби вычисления сингулярных чисел и векторов}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)) &amp;lt;ref&amp;gt;{{Cite book|title = Handbook on Parallel Computing and Statistics, p.126 |last = Erricos|first = John |url=https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf}}&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.1). &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.2). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде. &amp;lt;ref&amp;gt;{{Cite book|title =  Вычислительная линейная алгебра, p.263 |last = Деммель|first = Дж.}}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. Erricos John, Handbook on Parallel Computing and Statistics, p. 126 [https://www.irisa.fr/sage/bernard/publis/SVD-Chapter06.pdf]&lt;br /&gt;
&lt;br /&gt;
4. Singular Value Decomposition - LAPACK Driver Routines [https://software.intel.com/en-us/node/521149]&lt;br /&gt;
&lt;br /&gt;
5. Parallelism in the Intel® Math Kernel Library [https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library]&lt;br /&gt;
&lt;br /&gt;
6. JacobiSVD Class Template Reference [https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Infobox&amp;diff=678</id>
		<title>Template:Infobox</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Infobox&amp;diff=678"/>
		<updated>2016-10-15T08:30:11Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;{| style=&amp;quot;border-collapse: separate; border-spacing: 4px; border: 1px solid darkgray; margin: 1em 1em 1em 0; background-color: #f9f9f9; border: 1px #aaa solid; clear: right; f...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| style=&amp;quot;border-collapse: separate; border-spacing: 4px; border: 1px solid darkgray; margin: 1em 1em 1em 0; background-color: #f9f9f9; border: 1px #aaa solid; clear: right; float: right; {{{style-options}}}&amp;quot;&lt;br /&gt;
{{#if: {{{title|}}} |&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; style=&amp;quot;background-color:#cfc; text-align: center; font-size: 120%; font-weight: bold;&amp;quot; {{!}} {{{title}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{title-1|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; style=&amp;quot;background-color:#ddf; text-align: center; font-size: 110%; font-weight: bold;&amp;quot; {{!}} {{{title-1}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-1.1|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-1.1}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-1.1}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-1.2|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-1.2}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-1.2}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-1.3|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-1.3}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-1.3}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-1.4|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-1.4}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-1.4}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-1.5|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-1.5}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-1.5}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{title-2|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; style=&amp;quot;background-color:#ddf; text-align: center; font-size: 110%; font-weight: bold;&amp;quot; {{!}} {{{title-2}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-2.1|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-2.1}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-2.1}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-2.2|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-2.2}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-2.2}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-2.3|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-2.3}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-2.3}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-2.4|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-2.4}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-2.4}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}{{#if: {{{data-2.5|}}} |&amp;amp;nbsp;&lt;br /&gt;
{{!}} style=&amp;quot;background-color:#eef; padding: 0.2em; font-weight: bold;&amp;quot; {{!}} {{{label-2.5}}}&lt;br /&gt;
{{!}} style=&amp;quot;padding: 0.2em;&amp;quot; {{!}} {{{data-2.5}}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
}}&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Infobox]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=677</id>
		<title>Template:Level-a</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Level-a&amp;diff=677"/>
		<updated>2016-10-15T08:29:35Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;Уровень алгоритма&amp;lt;/indic...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;indicator name=&amp;quot;level-a&amp;quot;&amp;gt;[[File:A-chameleon-square-64x64.png|32px|link=Project:Уровни классификации|Уровень алгоритма]]&amp;lt;/indicator&amp;gt;[[Категория:Уровень алгоритма]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[en:Template:Level-a]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=676</id>
		<title>Template:Algorithm</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=676"/>
		<updated>2016-10-15T08:28:20Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{level-a}}&lt;br /&gt;
{{infobox&lt;br /&gt;
| style-options=max-width: 40%&lt;br /&gt;
| title={{{name|}}}&lt;br /&gt;
| title-1={{#if: {{{serial_complexity|}}}{{{input_data|}}}{{{output_data|}}} | Последовательный алгоритм}}&lt;br /&gt;
| label-1.1=Последовательная сложность&lt;br /&gt;
| data-1.1={{{serial_complexity|}}}&lt;br /&gt;
| label-1.2=Объём входных данных&lt;br /&gt;
| data-1.2={{{input_data|}}}&lt;br /&gt;
| label-1.3=Объём выходных данных&lt;br /&gt;
| data-1.3={{{output_data|}}}&lt;br /&gt;
| title-2={{#if: {{{parallel_complexity|}}}{{{pf_height|}}}{{{pf_width|}}} | Параллельный алгоритм}}&lt;br /&gt;
| label-2.1=Параллельная сложность&lt;br /&gt;
| data-2.1={{{parallel_complexity|}}}&lt;br /&gt;
| label-2.2=Высота ярусно-параллельной формы&lt;br /&gt;
| data-2.2={{{pf_height|}}}&lt;br /&gt;
| label-2.3=Ширина ярусно-параллельной формы&lt;br /&gt;
| data-2.3={{{pf_width|}}}&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;source lang=html4strict&amp;gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Разложение Холецкого&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=675</id>
		<title>Template:Algorithm</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=675"/>
		<updated>2016-10-15T08:25:56Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{level-a}}&lt;br /&gt;
{{infobox&lt;br /&gt;
| style-options=max-width: 40%&lt;br /&gt;
| title={{{name|}}}&lt;br /&gt;
| title-1={{#if: {{{serial_complexity|}}}{{{input_data|}}}{{{output_data|}}} | Последовательный алгоритм}}&lt;br /&gt;
| label-1.1=Последовательная сложность&lt;br /&gt;
| data-1.1={{{serial_complexity|}}}&lt;br /&gt;
| label-1.2=Объём входных данных&lt;br /&gt;
| data-1.2={{{input_data|}}}&lt;br /&gt;
| label-1.3=Объём выходных данных&lt;br /&gt;
| data-1.3={{{output_data|}}}&lt;br /&gt;
| title-2={{#if: {{{parallel_complexity|}}}{{{pf_height|}}}{{{pf_width|}}} | Параллельный алгоритм}}&lt;br /&gt;
| label-2.1=Параллельная сложность&lt;br /&gt;
| data-2.1={{{parallel_complexity|}}}&lt;br /&gt;
| label-2.2=Высота ярусно-параллельной формы&lt;br /&gt;
| data-2.2={{{pf_height|}}}&lt;br /&gt;
| label-2.3=Ширина ярусно-параллельной формы&lt;br /&gt;
| data-2.3={{{pf_width|}}}&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;source lang=html4strict&amp;gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Разложение Холецкого&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en:Template:Algorithm]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=671</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=671"/>
		<updated>2016-10-15T08:20:13Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg|center|thumb|Рисунок 1. Процедура вращения]]&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы (Рис.1). Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма (Рис.2(a)).&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg|center|thumb|Рисунок 2(а) и 2(b). Реализация алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. &lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны, можно вычислять независимо (Рис.2(b)) &amp;lt;ref&amp;gt;{{Cite book|title = Handbook on Parallel Computing and Statistics, p.126 |last = Erricos|first = John}}&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.2. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.1). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. https://software.intel.com/en-us/node/521149&lt;br /&gt;
&lt;br /&gt;
4. https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&lt;br /&gt;
&lt;br /&gt;
5. https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=670</id>
		<title>Template:Algorithm</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=670"/>
		<updated>2016-10-15T08:19:55Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=666</id>
		<title>Template:Algorithm</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=666"/>
		<updated>2016-10-15T08:12:14Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;2n^2 + n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=665</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=665"/>
		<updated>2016-10-15T08:11:32Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.2. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.1). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. https://software.intel.com/en-us/node/521149&lt;br /&gt;
&lt;br /&gt;
4. https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&lt;br /&gt;
&lt;br /&gt;
5. https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=664</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=664"/>
		<updated>2016-10-15T08:10:12Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.2. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.1). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. https://software.intel.com/en-us/node/521149&lt;br /&gt;
&lt;br /&gt;
4. https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&lt;br /&gt;
&lt;br /&gt;
5. https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=663</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=663"/>
		<updated>2016-10-15T08:04:58Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.2. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.1). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. https://software.intel.com/en-us/node/521149&lt;br /&gt;
&lt;br /&gt;
4. https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&lt;br /&gt;
&lt;br /&gt;
5. https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=662</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=662"/>
		<updated>2016-10-15T08:04:46Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/*{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}*/&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=1,2,3,...,n-1&amp;lt;/math&amp;gt; параллельно выполнить вращение в позиции &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=1,2,3,...,\lceil\frac{1}{2}(n-k)\rceil,\\&lt;br /&gt;
j=(n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=(n-k+2),(n-k+3),...,n-\lceil\frac{1}{2}k\rceil,\\&lt;br /&gt;
j=(2n-k+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* For &amp;lt;math&amp;gt;k=n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
i=2,3,...,\lceil\frac{1}{2}n\rceil,\\&lt;br /&gt;
j=(n+2)-i&lt;br /&gt;
\end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений (Рис.2. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне (Рис.1). Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм считается наиболее точным для вычисления сингулярных чисел в случае, если матрица представима в специальном виде.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычисление SVD разложения матрицы методом Якоби реализовано в следующих библиотеках:&lt;br /&gt;
&lt;br /&gt;
1. В реализации Intel MKL процедуры BLAS Level 3 являются параллельными по потокам, таким образом, любая функция, обращающая к ним будет использовать параллельные вычисления. Функции из LAPACK в MKL могут иметь или не иметь параллельные по потокам сегменты. Ни BLAS Level 3, ни LAPACK в реализации MKL не используют параллельность по процессам.&lt;br /&gt;
&lt;br /&gt;
2. LAPACK: не предназначен для систем с распределенной памятью, возможна параллельность по потокам&lt;br /&gt;
&lt;br /&gt;
3. scaLAPACK: как и в случае с MKL, все процедуры LAPACK в scaLAPACK не являются параллельными по потокам. Использует параллельные инструкции современных процессоров. Не использует параллельность по потокам или процессам.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;br /&gt;
&lt;br /&gt;
3. https://software.intel.com/en-us/node/521149&lt;br /&gt;
&lt;br /&gt;
4. https://software.intel.com/en-us/articles/parallelism-in-the-intel-math-kernel-library&lt;br /&gt;
&lt;br /&gt;
5. https://eigen.tuxfamily.org/dox/classEigen_1_1JacobiSVD.html&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=661</id>
		<title>Template:Algorithm</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=Template:Algorithm&amp;diff=661"/>
		<updated>2016-10-15T08:03:44Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: Created page with &amp;quot;{{algorithm | name              = Разложение Холецкого | serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt; | pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; | pf_width...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Разложение Холецкого&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;\frac{n (n + 1)}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna&amp;diff=587</id>
		<title>User:GrishinaAnna</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna&amp;diff=587"/>
		<updated>2016-10-14T11:49:48Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: GrishinaAnna moved page User:GrishinaAnna to User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов]]&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=586</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=586"/>
		<updated>2016-10-14T11:49:47Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: GrishinaAnna moved page User:GrishinaAnna to User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&#039;&#039;&#039;тут большая хрень которую надо перепечатать &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне. Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=582</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=582"/>
		<updated>2016-10-14T11:31:47Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&#039;&#039;&#039;тут большая хрень которую надо перепечатать &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне. Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=581</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=581"/>
		<updated>2016-10-14T11:30:39Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;\name = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&#039;&#039;&#039;тут большая хрень которую надо перепечатать &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне. Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=579</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=579"/>
		<updated>2016-10-14T11:30:16Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;name = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&#039;&#039;&#039;тут большая хрень которую надо перепечатать &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне. Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=577</id>
		<title>User:GrishinaAnna/Метод Якоби вычисления сингулярных чисел и векторов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/pool/index.php?title=User:GrishinaAnna/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AF%D0%BA%D0%BE%D0%B1%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB_%D0%B8_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=577"/>
		<updated>2016-10-14T11:23:25Z</updated>

		<summary type="html">&lt;p&gt;GrishinaAnna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Метод Якоби вычисления сингулярных чисел и векторов ==&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод Якоби вычисления сингулярных чисел и векторов&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt; &lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участник:GrishinaAnna|Гришина Анна]] (группа 604), [[Участница:Наталия Чудновская|Наталия Чудновская]] (группа 611)&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Метод Якоби позволяет получить разложение произвольной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;  в виде &amp;lt;math&amp;gt;G=USV^*&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; — унитарные матрицы, &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; — диагональная матрица с вещественными положительными числами на диагонали. Диагональные элементы матрицы  называются сингулярными числами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, а столбцы матриц  и  левыми и правыми сингулярными векторами соответственно.&lt;br /&gt;
&lt;br /&gt;
В основе метода лежит утверждение о том, что собственными значениями симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; являются квадраты сингулярных чисел, а соответствующие ортонормированные собственные векторы – правыми сингулярными векторами. Для вычисления собственных значений и собственных векторов симметричной матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; используется метод односторонних вращений (неявный метод Якоби), на каждом шаге которого вычисляется вращение Якоби &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;. С его помощью матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; неявно пересчитывается в &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Вращение выбрано так, чтобы пара внедиагональных элементов из &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; обратилась в нуль в матрице &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt;. Однако, &amp;lt;math&amp;gt;J^TG^TGJ&amp;lt;/math&amp;gt; не вычисляется в явном виде; вместо неё вычисляется матрица &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt;, которая подается на вход на следующем шаге алгоритма. Алгоритм выполняется, пока &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; не станет достаточно близка к диагональной матрице, после чего вычисляются собственные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;, полученной на последнем шаге, которые принимаются за сингулярные числа. Правые сингулярные векторы получаются в результате накопления произведений вращений Якоби. Левые сингулярные векторы вычисляются как собственные векторы полученной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Метод Якоби для вычисления сингулярных значений и векторов является самым медленным из имеющихся, но тем не менее, интерес к нему сохраняется, потому что для некоторых типов матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; он способен вычислять числа и сингулярные векторы намного точнее, чем другие методы. Так, например, метод Якоби вычисляет сингулярные числа матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; с высокой точностью, если &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; может быть представлена в виде &amp;lt;math&amp;gt;G=DX&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; – диагональная матрица, а &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; – хорошо обусловлена. Выигрыш метода Якоби в этом случае перед другими алгоритмами объясняется следующим образом: в методе Якоби заданная матрица обрабатывается без предварительного приведения к двухдиагональному виду, в то время как другие алгоритмы включают в себя приведение матрицы к двухдиагональной форме, из-за чего и теряют все верные разряды во всех сингулярных числах, кроме старшего.&lt;br /&gt;
&lt;br /&gt;
Следует иметь в виду, что метод Якоби эффективен при не очень больших размерах матрицы – максимум до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ~ &amp;lt;math&amp;gt;100&amp;lt;/math&amp;gt;. Дело не только в том, что метод не будет сходиться за конечное время, дело еще и в излишне большом количестве операций, которое приведет к ошибкам округления и потере точности.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: Матрица &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  - сингулярные числа, матрица &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; левых сингулярных векторов и матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов. &lt;br /&gt;
&lt;br /&gt;
Описание используемой в алгоритме процедуры одностороннего вращения входной матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;  &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;:&lt;br /&gt;
 proc &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation &amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
     вычислить &amp;lt;math&amp;gt;a_{jj} = (G^TG)_{jj}, a_{jk} = (G^TG)_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;a_{kk} = (G^TG)_{kk}&amp;lt;/math&amp;gt;&lt;br /&gt;
     if &amp;lt;math&amp;gt;|a_{jk}|&amp;lt;/math&amp;gt; не слишком мал&lt;br /&gt;
         &amp;lt;math&amp;gt;&lt;br /&gt;
         \begin{align}&lt;br /&gt;
         \tau &amp;amp;= {a_{jj} - a_{kk}}/{2a_{jk}} \\&lt;br /&gt;
         t &amp;amp;= {sign(\tau)}/(|\tau| + \sqrt{1 + \tau^2}) \\&lt;br /&gt;
         c &amp;amp;= 1/(\sqrt{1 + t^2}) \\&lt;br /&gt;
         s &amp;amp;= ct \\&lt;br /&gt;
         G &amp;amp;= GR(j,k,\theta) \  \dots c=cos\theta, s=sin\theta \end{align}&amp;lt;/math&amp;gt;&lt;br /&gt;
         if нужны правые сингулярные векторы &lt;br /&gt;
             &amp;lt;math&amp;gt;J = JR(j,k,\theta)&amp;lt;/math&amp;gt;&lt;br /&gt;
         end if&lt;br /&gt;
     end if&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;math&amp;gt;R(j,k,\theta)&amp;lt;/math&amp;gt; – матрица вращения Якоби, которая выбирается так, чтобы обнулить пару внедиагональных элементов.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
J_i =  R(j,k,\theta) = &lt;br /&gt;
\begin{matrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
j \\&lt;br /&gt;
  \\&lt;br /&gt;
k \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
  \\&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;  &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{bmatrix}&lt;br /&gt;
  &amp;amp; 1 &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp; 1 &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp; \ddots &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \cos(\theta) &amp;amp;        &amp;amp; -\sin(\theta) &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp; \ddots &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp; \sin(\theta) &amp;amp;        &amp;amp; \cos(\theta)  &amp;amp;         &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp; \ddots  &amp;amp;    &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp; 1  &amp;amp;   \\&lt;br /&gt;
  &amp;amp;   &amp;amp;   &amp;amp;        &amp;amp;              &amp;amp;        &amp;amp;               &amp;amp;         &amp;amp;    &amp;amp; 1 \\&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод односторонних вращений (основной алгоритм):&lt;br /&gt;
&lt;br /&gt;
Для всех недиагональных элементов матрицы &amp;lt;math&amp;gt;(G^TG)^{(i)} = A^{(i)}&amp;lt;/math&amp;gt; подряд, т.е. &amp;lt;math&amp;gt;(A_{12}^{(i)}, A_{13}^{(i)},\dots, A_{1n}^{(i)}, A_{23}^{(i)}, A_{24}^{(i)},\dots, A_{2n}^{(i)},\dots, A_{n-1n}^{(i)})&amp;lt;/math&amp;gt; проделывать следующее:&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| \le \varepsilon &amp;lt;/math&amp;gt;, то переходим к следующему элементу.&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;|A_{jk}^{(i)}| &amp;gt; \varepsilon &amp;lt;/math&amp;gt;, то выполняем вращение в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt;, т.е. вызываем процедуру &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;, после чего переходим к началу алгоритма.&lt;br /&gt;
&lt;br /&gt;
Если при очередном проходе всей матрицы ни одного вращения не было, то алгоритм переходит непосредственно к вычислению искомых значений:&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;\sigma_{i} = ||G(:,i)||_{2}&amp;lt;/math&amp;gt; (2-норма &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца в &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt;U = [u_{1}, \dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:,i)/\sigma_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Положить &amp;lt;math&amp;gt; V = J&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; -- накопленное произведение вращений Якоби.&lt;br /&gt;
         &lt;br /&gt;
При каждом элементарном вращении в плоскости &amp;lt;math&amp;gt;(jk)&amp;lt;/math&amp;gt; сумма квадратов модулей начальных элементов убывает в точности на &amp;lt;math&amp;gt;2 |A_{jk}^{(i)}|^2&amp;lt;/math&amp;gt;. Однако элементы &amp;lt;math&amp;gt;|A_{jk}^{(i)}|&amp;lt;/math&amp;gt;, приведенные к нулю на &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-й итерации, на последующей итерации немного возрастают. При &amp;lt;math&amp;gt;i \to \inf&amp;lt;/math&amp;gt; получается монотонно убывающая ограниченная снизу нулем последовательность . Это и означает сходимость метода, причем &lt;br /&gt;
&amp;lt;math&amp;gt; A(i) \to S = diag(\sigma_{1}, \dots, \sigma_{n}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма===&lt;br /&gt;
Основную сложность в алгоритме представляет многократное обращение к процедуре &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039;, сложность которой составляет &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; (см. раздел [[глоссарий#Макроструктура алгоритма|Макроструктура алгоритма]]). Всего таких обращений по меньшей мере  &amp;lt;math&amp;gt;\frac{n^2-n}{2}&amp;lt;/math&amp;gt;, т.к. процедура должна сработать как минимум один раз для каждого наддиагонального элемента, чтобы его обнулить. Также серьезную сложность представляет вычисление &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; на каждом шаге, сложность которого составляет &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Основная проблема заключается в том, что обнуленный на шаге &amp;lt;math&amp;gt;(i)&amp;lt;/math&amp;gt; элемент может снова стать ненулевым на шаге &amp;lt;math&amp;gt;(i+1)&amp;lt;/math&amp;gt;. Из-за этого число необходимых вращений изначально недетерминировано.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Рассмотрим подробно схему работы, а также вычислительную сложность процедуры &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	Вычисление &amp;lt;math&amp;gt;A_{jj} = (G^TG)_{jj}&amp;lt;/math&amp;gt; требует &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; операцию сложения (т.к. нет необходимости явно вычислять произведение двух матриц). Столько же операций нужно и для вычисления &amp;lt;math&amp;gt;A_{jk}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;A_{kk}&amp;lt;/math&amp;gt;. То есть, всего &amp;lt;math&amp;gt;3n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; операции сложения на первом шаге.&lt;br /&gt;
&lt;br /&gt;
2)	Вычисления &amp;lt;math&amp;gt;\tau, t, c, s&amp;lt;/math&amp;gt; не представляют значимой вычислительной сложности.&lt;br /&gt;
&lt;br /&gt;
3)	Заметим, что матрица &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; отличается от единичной лишь в &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt; элементах. Это значит, что в матрице &amp;lt;math&amp;gt;GJ&amp;lt;/math&amp;gt; все столбцы, кроме двух, будут совпадать со столбцами матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;. А для вычисления двух новых столбцов, при учете вида матрицы &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;, достаточно &amp;lt;math&amp;gt;4n&amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt; сложений. Аналогичное число операций требуется и для вычисления произведения &amp;lt;math&amp;gt;JR(j,k,\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4)	Итого, процедура &#039;&#039;&#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&#039;&#039; &amp;lt;math&amp;gt;(G, j, k)&amp;lt;/math&amp;gt; требует порядка &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
В качестве следующей макрооперации можно выделить вычисление &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; на каждом шаге алгоритма.&lt;br /&gt;
&lt;br /&gt;
После выполнения алгоритма односторонних вращений, когда матрица &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt; станет достаточно близка к диагональной, необходимо вычислить искомые матрицы &amp;lt;math&amp;gt;S, U, V &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1)	&amp;lt;math&amp;gt;\sigma_{i} = ||G(:, i)||_{2}&amp;lt;/math&amp;gt;, т.е. для вычисления &amp;lt;math&amp;gt;\sigma_{i}&amp;lt;/math&amp;gt;  потребуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения, а для вычисления &amp;lt;math&amp;gt;S = diag(\sigma_{i})&amp;lt;/math&amp;gt; -- &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
2)	&amp;lt;math&amp;gt;U = [u_{1},\dots, u_{n}]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;u_{i} = G(:, i)/ \sigma_{i}&amp;lt;/math&amp;gt;. Значит, вычисление &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; потребует &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
3)      Матрица &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; правых сингулярных векторов формируется в ходе работы алгоритма: &amp;lt;math&amp;gt;V = J&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Схема реализации последовательного алгоритма подробно описана в разделе [[глоссарий#Математическое описание алгоритма|&#039;&#039;Математическое описание алгоритма&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
На каждом шаге алгоритма вычисляется &amp;lt;math&amp;gt;(G^TG)&amp;lt;/math&amp;gt; и вызывается процедура вращения. Сложность первого вычисления &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;, а второго – &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Т.е. общая сложность шага алгоритма равна &amp;lt;math&amp;gt;O(n^3)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Построим информационный граф отдельно для процедуры вращения, а затем для всего алгоритма с обращениями к процедуре вращения.&lt;br /&gt;
&lt;br /&gt;
Для процедуры вращения в качестве узлов графа выберем точки на равномерной сетке &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – размерность матрицы. Для вычисления коэффициентов в матрице поворота требуется вычислить значения &amp;lt;math&amp;gt;a_{ii}, a_{ji}, a_{jj}&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G^TG&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того как посчитаны коэффициенты, необходимо пересчитать значения в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцах матрицы. Эти значения зависят от входных значений соответствующих элементов и рассчитанных ранее &amp;lt;math&amp;gt;\cos (\theta)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sin(\theta)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Граф выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[File:graf_1_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф для всего алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:graf_2_chudnovskaya.jpg]]&lt;br /&gt;
&lt;br /&gt;
Как было показано ранее, процедура вращения в плоскости &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; зависит только от столбцов &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и рассчитывает новые значения только для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцов, причем новое значение вычисляется для каждого элемента в столбце.&lt;br /&gt;
С учетом сказанного выше будем строить граф вычислений, рассматривая каждый столбец матрицы G как многомерную переменную и введя обозначение &amp;lt;math&amp;gt;G(:,i)&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-го столбца.&lt;br /&gt;
&lt;br /&gt;
В зависимости от порядка перебора пар элементов возможны различные графы, параллельные по данным в большей и меньшей степени.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующий простой перебор:&lt;br /&gt;
&lt;br /&gt;
      for &amp;lt;math&amp;gt;i=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
          for &amp;lt;math&amp;gt;j=1:n;&amp;lt;/math&amp;gt;&lt;br /&gt;
              calculate&amp;lt;math&amp;gt;(i,j);&amp;lt;/math&amp;gt;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
При таком переборе для каждого последующего элемента требуется столбец из предыдущего внутреннего цикла.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, как было показано ранее, процедура односторонних вращений зависит и изменяет только  &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; столбцы. Таким образом пары &amp;lt;math&amp;gt;(i_1,j_1)&amp;lt;/math&amp;gt; И &amp;lt;math&amp;gt;(i_2,j_2)&amp;lt;/math&amp;gt; такие, что все &amp;lt;math&amp;gt;i_1,i_2,j_1,j_2&amp;lt;/math&amp;gt; – различны можно вычислять независимо.&lt;br /&gt;
&lt;br /&gt;
Одним из вариантов реализации такого подхода является следующий. Будем строить пары &amp;lt;math&amp;gt;(i,j)&amp;lt;/math&amp;gt; специального вида:&#039;&#039;&#039;тут большая хрень которую надо перепечатать &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма ===&lt;br /&gt;
Рассмотрим ресурс параллелизма внутри процедуры вращений. &lt;br /&gt;
&lt;br /&gt;
На каждом из n ярусов требуется выполнить 3 умножения, которые могут быть произведены параллельно. Обратим внимание, что сложения тоже могут быть выполнены параллельно с учетом ассоциативности операции и с применением редукции.&lt;br /&gt;
&lt;br /&gt;
Далее для вычисления обновленных столбцов матрицы на каждом из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов в правой группе вершин требуется выполнить 4 умножения и 2 сложения. Все ярусы могут быть вычислены параллельно.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим возможность параллельного вычисления на более высоком уровне. Как было показано ранее, можно рассматривать столбцы матрицы как многомерные переменные.&lt;br /&gt;
&lt;br /&gt;
При простом переборе, изображенном на графе слева, данные каждый раз зависят от предыдущих вычислений, однако, как было сказано ранее, при изменении порядка перебора возникает возможность параллельного вычисления вращений. При использовании указанной в разделе 1.7 схеме параллельно могут вычисляться &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; пар.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные ===&lt;br /&gt;
Входные данные: матрица &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;×&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: диагональная матрица &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, диагональными элементами которой являются сингулярные числа, матрицы &amp;lt;math&amp;gt;U&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; левых и правых сингулярных векторов.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;2n^2+n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;G = DX&amp;lt;/math&amp;gt; - матрица порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, причем &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; невырожденны и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - диагональная матрица. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt; - матрица, полученная из &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; в результате m-кратного обращения к процедуре &#039;&#039;&#039;One-Sided-Jacobi-Rotation&#039;&#039;&#039;&amp;lt;math&amp;gt;(G,j,k)&amp;lt;/math&amp;gt; в арифметике с плавающей точкой. Обозначим через &amp;lt;math&amp;gt;\sigma_{1} \geq \ldots \geq \sigma_{n}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{\sigma_{1}} \geq \ldots \geq \tilde{\sigma_{n}}&amp;lt;/math&amp;gt; сингулярные числа матриц &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\tilde{G}&amp;lt;/math&amp;gt;. Тогда&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;\frac{\vert\sigma_{i}-\tilde{\sigma_{i}}\vert}{\sigma_{i}} \leq O(m\varepsilon)\kappa(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\kappa(X)=\Vert X \Vert \cdot \Vert X^{-1} \Vert&amp;lt;/math&amp;gt; есть число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Другими словами, относительная погрешность вычисленных сингулярных чисел мала, если мало число обусловленности матрицы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
1. Дж. Деммель Вычислительная линейная алгебра. Изд. Мир, 2001.&lt;br /&gt;
&lt;br /&gt;
2. Gene H. Golub, Charles F. Van Loan Matrix Computations, 3rd edition. The John Hopkins University Press&lt;/div&gt;</summary>
		<author><name>GrishinaAnna</name></author>
	</entry>
</feed>