<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=ASA</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=ASA"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/ASA"/>
	<updated>2026-10-22T21:20:29Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BB%D0%BE%D1%82%D0%BD%D1%8B%D1%85_%D0%BD%D0%B5%D0%BE%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86_(%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82)&amp;diff=30388</id>
		<title>Перемножение плотных неособенных матриц (последовательный вещественный вариант)</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BB%D0%BE%D1%82%D0%BD%D1%8B%D1%85_%D0%BD%D0%B5%D0%BE%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86_(%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82)&amp;diff=30388"/>
		<updated>2026-01-19T10:24:41Z</updated>

		<summary type="html">&lt;p&gt;ASA: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Перемножение плотных неособенных матриц&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2mnl&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2ml&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;mn+nl&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;ml&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перемножение матриц&#039;&#039;&#039; - одна из базовых задач в алгоритмах линейной алгебры, широко применяется в большом количестве разных методов.&lt;br /&gt;
Здесь мы рассмотрим умножение &amp;lt;math&amp;gt;C = AB&amp;lt;/math&amp;gt;&amp;amp;nbsp; плотных неособенных матриц (последовательный вещественный вариант), то есть тот вариант, где никак не используются ни специальный вид матрицы, ни ассоциативные свойства операции сложения&amp;lt;ref&amp;gt;В.В.Воеводин, Ю.А.Кузнецов. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: плотная матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;), плотная матрица &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_{ij}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: плотная матрица &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Формулы метода:&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
c_{ij} = \sum_{k = 1}^{n} a_{ik} b_{kj}, \quad i \in [1, m], \quad j \in [1, l].&lt;br /&gt;
\end{align}&lt;br /&gt;
&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;l&amp;lt;/math&amp;gt;) вычислений умножения матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на столбцы матрицы &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, или (при более детальном рассмотрении), из множественных (всего их &amp;lt;math&amp;gt;ml&amp;lt;/math&amp;gt;) скалярных произведений строк матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на столбцы матрицы &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{k = 1}^{n} a_{ik} b_{kj}&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;ml&amp;lt;/math&amp;gt;) вычисления скалярных произведений строк матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на столбцы матрицы &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{k = 1}^{n} a_{ik} b_{kj}&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;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;  и для всех &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; выполняются&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;c_{ij} = \sum_{k = 1}^{n} a_{ik} b_{kj}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Особо отметим, что вычисления сумм вида &amp;lt;math&amp;gt;\sum_{k = 1}^{n} a_{ik} b_{kj}&amp;lt;/math&amp;gt; производят в режиме накопления прибавлением к текущему (временному) значению вычисляемого элемента матрицы &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt; произведений &amp;lt;math&amp;gt;a_{ik} b_{kj}&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, &#039;&#039;&#039;c возрастанием&#039;&#039;&#039; &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, вначале все элементы инициализируются нулями. При суммировании &amp;quot;по убыванию&amp;quot; общая схема принципиально не отличается и потому нами не рассматривается. Другие порядки выполнения суммирования приводят к изменению параллельных свойств алгоритма и будут рассматриваться нами в отдельных описаниях.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для умножения двух квадратных матриц порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; (т.е. при &amp;lt;math&amp;gt;m=n=l&amp;lt;/math&amp;gt;) в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* по &amp;lt;math&amp;gt;n^3&amp;lt;/math&amp;gt; умножений и сложений.&lt;br /&gt;
&lt;br /&gt;
Для умножения матрицы размером &amp;lt;math&amp;gt;m&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;l&amp;lt;/math&amp;gt; столбцов в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* по &amp;lt;math&amp;gt;mnl&amp;lt;/math&amp;gt; умножений и сложений.&lt;br /&gt;
 &lt;br /&gt;
При этом использование режима накопления требует совершения умножений и сложений в режиме двойной точности (или использования функции вроде DPROD в Фортране), что ещё больше увеличивает затраты во времени, требуемом для выполнения умножения матриц.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, алгоритм умножения матриц относится к алгоритмам &#039;&#039;с кубической сложностью&#039;&#039; (в случае неквадратных матриц - с &#039;&#039;трилинейной&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем [[глоссарий#Граф алгоритма|граф алгоритма]] как аналитически, так и в виде рисунка.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма умножения плотных матриц состоит из одной группы вершин, расположенной в целочисленных узлах трёхмерной области, соответствующая ей операция  &amp;lt;math&amp;gt;a+bc&amp;lt;/math&amp;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;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;:&lt;br /&gt;
** при &amp;lt;math&amp;gt;k = 1&amp;lt;/math&amp;gt; константа &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;; &lt;br /&gt;
** при &amp;lt;math&amp;gt;k &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине с координатами &amp;lt;math&amp;gt;i, j, k-1&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — элемент &#039;&#039;входных данных&#039;&#039;, а именно  &amp;lt;math&amp;gt;a_{ik}&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - элемент &#039;&#039;входных данных&#039;&#039; &amp;lt;math&amp;gt;b_{kj}&amp;lt;/math&amp;gt;; &lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является:&lt;br /&gt;
* при &amp;lt;math&amp;gt;k &amp;lt; n&amp;lt;/math&amp;gt; - &#039;&#039;промежуточным данным&#039;&#039; алгоритма;&lt;br /&gt;
* при &amp;lt;math&amp;gt;k = n&amp;lt;/math&amp;gt; - выходным данным &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[file:Dense mtrx product.png|thumb|center|800px|Рисунок 1. Умножение плотных матриц с отображением выходных данных]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
Интерактивное изображение графа алгоритма без входных и выходных данных для случая перемножения двух квадратных матриц порядка 3 и 4&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{#widget:Algoviewer&lt;br /&gt;
|url=mat_mul/mat_mul_3/Algo_view_matrix3.html&lt;br /&gt;
|width=600&lt;br /&gt;
|height=400&lt;br /&gt;
|border=1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{#widget:Algoviewer&lt;br /&gt;
|url=mat_mul/mat_mul_4/Algo_view_matrix4.html&lt;br /&gt;
|width=600&lt;br /&gt;
|height=400&lt;br /&gt;
|border=1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для алгоритма умножения квадратных матриц порядка n в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* по &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений (в каждом из ярусов — &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
Для умножения матрицы размером &amp;lt;math&amp;gt;m&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;l&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;ml&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
При этом использование режима накопления требует совершения умножений и вычитаний в режиме двойной точности, а в параллельном варианте это означает, что практически все промежуточные вычисления для выполнения алгоритма в режиме накопления должны быть двойной точности. В отличие от последовательного варианта это означает некоторое увеличение требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матриц относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;квадратичной&#039;&#039; (для квадратных матриц) или &#039;&#039;билинейной&#039;&#039; (для матриц общего вида).&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;), матрица &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_{ij}&amp;lt;/math&amp;gt;)).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;mn+nl&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: матрица &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;ml&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;квадратичным&#039;&#039; или &#039;&#039;билинейным&#039;&#039; (отношение кубической или трилинейной к линейной). &lt;br /&gt;
&lt;br /&gt;
При этом вычислительная мощность алгоритма умножения матриц, как отношение числа операций к суммарному объему входных и выходных данных – &#039;&#039;линейно&#039;&#039;.&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;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         &lt;br /&gt;
	DO  I = 1, M&lt;br /&gt;
        DO  J = 1, L&lt;br /&gt;
		S = 0.&lt;br /&gt;
		DO  K = 1, N&lt;br /&gt;
			S = S + DPROD(A(I,K), B(K,J))&lt;br /&gt;
		END DO	&lt;br /&gt;
	        C(I, J) = S&lt;br /&gt;
        END DO&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При этом для реализации режима накопления переменная &amp;lt;math&amp;gt;S&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
[[Категория:Матричные операции]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dense matrix multiplication (serial version for real matrices)]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=30387</id>
		<title>Глоссарий</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=30387"/>
		<updated>2026-01-16T10:48:03Z</updated>

		<summary type="html">&lt;p&gt;ASA: /* Параллельная сложность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Временна́я локальность ===&lt;br /&gt;
&#039;&#039;&#039;Временная локальность&#039;&#039;&#039; (temporal locality) показывает среднее число обращений по одному адресу в память за время исполнения всей программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная мощность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная мощность&#039;&#039;&#039; (computational power) алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная сложность&#039;&#039;&#039; (computational complexity) задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; - количество основных вычислительных шагов лучшего последовательного алгоритма, необходимых для решения задачи на одном процессоре. Вычислительная сложность обычно является некоторой функцией от размера входных данных рассматриваемого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительное ядро&#039;&#039;&#039; (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Граф алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Граф алгоритма&#039;&#039;&#039; (algorithm graph) - это ориентированный ациклический мультиграф, вершины которого соответствуют операциям алгоритма, а дуги - передаче данных между ними. Вершины графа алгоритма могут соединяться несколькими дугами, в частности когда в качестве разных аргументов одной и той же операции используется одна и та же величина. Граф алгоритма почти всегда является параметризованным графом. В частности, его вид часто зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма используется как удобное представление алгоритма при исследовании его структуры, ресурса параллелизма, а также других свойств. Его можно рассматривать как параметризованную информационную историю. Он сохраняет её информативность, при этом обладая компактностью за счёт параметризации. Разработана методика построения графа алгоритма по исходному тексту программ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также: [https://ru.wikipedia.org/wiki/Граф_алгоритма Граф алгоритма]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&#039;&#039;&#039;Детерминированность&#039;&#039;&#039; (determinacy) алгоритма - постоянство структуры вычислительного процесса. Алгоритм выдаёт уникальный и предопределённый результат для заданных входных данных.&lt;br /&gt;
&lt;br /&gt;
=== Избыточные вычисления ===&lt;br /&gt;
&#039;&#039;&#039;Избыточные вычисления&#039;&#039;&#039; (redundant computation) - понятие, которое используют для обозначения разных явлений в параллельных вычислениях. &lt;br /&gt;
* В понимании графовой модели вычислений это такие операции, результаты которых нигде не будут использованы. Такие операции появляются в результате ошибок программирования и подлежат удалению из алгоритма. &lt;br /&gt;
* Распространено также понимание термина как вычисления, которые &#039;&#039;выполняются более одного раза&#039;&#039; или на более чем одном процессоре. Избыточные вычисления могут использоваться либо в многопроцессорных системах, чтобы минимизировать обмены, либо при недостаточном объеме памяти для хранения всех вычисленных значений. &lt;br /&gt;
* Кроме этого, избыточными вычислениями можно назвать те операции, которые появляются при замене последовательного алгоритма на специальный параллельный. У последнего алгоритма больше операций, но меньше длина критического пути графа, этим и обосновывается замена алгоритма. В таком случае реальное ускорение параллельного алгоритма следует считать не в сравнении с однопроцессорной реализацией его самого, а в сравнении с реализацией последовательного алгоритма. В нашей открытой энциклопедии свойств алгоритмов именно последнее толкование термина применяется в категории [[http://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D1%81_%D0%B8%D0%B7%D0%B1%D1%8B%D1%82%D0%BE%D1%87%D0%BD%D1%8B%D0%BC%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8 Алгоритмы с избыточными вычислениями]].&lt;br /&gt;
&lt;br /&gt;
=== Конечный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Конечный параллелизм&#039;&#039;&#039; (finite parallelism) - параллелизм, определяемый информационной независимостью некоторых фрагментов в тексте программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Координатный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Координатный параллелизм&#039;&#039;&#039; (coordinate parallelism) - частный случай [[#Скошенный паралеллизм|скошенного параллелизма]], определяемый циклами ParDO, при котором информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность (обращений в память) ===&lt;br /&gt;
&#039;&#039;&#039;Локальность (обращений в память)&#039;&#039;&#039; (locality) - общее предположение о свойстве работы программ с данными. Заключается в том, что при обращении к некоторым данным велика вероятность, что в скором времени произойдет повторное обращение к тем же или расположенным рядом данным. В частности, на основе данного предположения построена работа кэш-памяти. Различают [[#Локальность команд|локальность команд]] и [[#Локальность использования данных|локальность использования данных]], а также [[#Пространственная локальность|пространственную]] и [[#Временна́я локальность|временну́ю]] локальность.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность вычислений ===&lt;br /&gt;
&#039;&#039;&#039;Локальность вычислений&#039;&#039;&#039; (computation locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - команды, из которых состоят программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность использования данных ===&lt;br /&gt;
&#039;&#039;&#039;Локальность использования данных&#039;&#039;&#039; (data locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - все данные, с которыми оперируют программы во время выполнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Массовый параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Массовый параллелизм&#039;&#039;&#039; (mass parallelism) - параллелизм, определяемый информационной независимостью итераций циклов программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость&#039;&#039;&#039; (scalability) - способность системы увеличивать свою [[#Производительность|производительность]] при добавлении ресурсов (обычно аппаратных). Система называется масштабируемой, если она способна увеличивать производительность пропорционально дополнительным ресурсам. Масштабируемость можно оценить через отношение прироста производительности системы к приросту используемых ей ресурсов. Чем ближе это отношение к единице, тем масштабируемость лучше.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость параллельной программы ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость параллельной программы&#039;&#039;&#039; (scalability of parallel program) определяется относительно конкретного компьютера и показывает, как изменяются динамические характеристики данной программы в зависимости от её [[#Параметры запуска|параметров запуска]].&lt;br /&gt;
&lt;br /&gt;
Наиболее часто рассматриваемые разновидности масштабируемости параллельных программ: [[#Сильная масштабируемость|сильная масштабируемость]], [[#Масштабируемость вширь|масштабируемость вширь]], [[#Слабая масштабируемость|слабая масштабируемость]].&lt;br /&gt;
&lt;br /&gt;
Если при одновременном увеличении числа процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; и [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; [[#Эффективность распараллеливания|эффективность распараллеливания]] &amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; остаётся прежней, то данную программу на данном компьютере можно считать масштабируемой.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость вширь ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость вширь&#039;&#039;&#039; (wide scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; при фиксированном числе процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка daps ===&lt;br /&gt;
&#039;&#039;&#039;Оценка daps&#039;&#039;&#039; (daps estimation) - предлагаемая оценка производительности работы с памятью в программе, равна числу выполненных обращений в память в секунду. Построена по аналогии с распространенной оценкой производительности программ — flop/s (floating point operations per second), которая оценивает число операций с плавающей запятой в секунду. Оценка flop/s показывает производительность всей программы с точки зрения производимых вычислений; в то время как daps оценивает производительность программы с точки зрения работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Данная оценка является машинно-зависимой — она вычисляется на основе данных аппаратных датчиков. Служит для проверки точности результатов разрабатываемых нами машинно-независимых оценок локальности, таких как [[#Оценка cvg|cvg]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка cvg ===&lt;br /&gt;
&#039;&#039;&#039;Оценка cvg&#039;&#039;&#039; (cvg estimation) - предлагаемая машинно-независимая оценка локальности обращений в памяти в программе. Рассмотрим первые N обращений в потоке («окно»), и затем разобьем ось ординат (виртуальный адрес обращений) на отрезки длины K – [X .. X+K],  [X+K .. X+2K], …, [Y-K .. Y], где [X, Y] - диапазон выделенной под рассматриваемые массивы виртуальной памяти. Таким образом, область построения профиля делится на прямоугольники размером KxN. &lt;br /&gt;
&lt;br /&gt;
Физический смысл такого прямоугольника (при правильно подобранных значениях K и N) заключается в том, что любая последовательность точек, попавших в один прямоугольник, всегда обладает хорошей как пространственной, так и временно́й локальностью. Действительно, при достаточно малом значении K в прямоугольник попадает небольшой локальный фрагмент виртуальной памяти, а, значит, соседние обращения по памяти в любом случае будут расположены близко друг относительно друга. А временна́я локальность внутри прямоугольника не может быть больше N, поэтому при достаточно малом N можно обеспечить и хорошую временну́ю локальность. Однако не имеет смысла брать слишком малые значения для K и N, поскольку в этом случае теряется полезная информация о хорошей локальности не попавшего в прямоугольник фрагмента профиля.&lt;br /&gt;
&lt;br /&gt;
Выделим те прямоугольники, в которые попадает хотя бы одно обращение. Чем меньше таких прямоугольников – тем больше точек попало в одни и те же прямоугольники, тем в общем случае лучше локальность. Пример разбиения профиля на прямоугольники приведен на рис. 1. Здесь для иллюстрации выделено три «окна», в каждом по 6 точек. В первом «окне» всего 2 непустых прямоугольника и самая хорошая локальность их трех вариантов. Во втором «окне» задействованы все 4 прямоугольника, при этом в каждый попало лишь по 1-2 обращения. Третье «окно» включает 3 непустых прямоугольника, и в этом варианте локальность лучше, чем у второго «окна», но хуже, чем у первого.&lt;br /&gt;
&lt;br /&gt;
[[file:cvg.png|thumb|center|500px|Рисунок 1. Пример разбиения профиля на прямоугольники]]&lt;br /&gt;
&lt;br /&gt;
Теперь сдвинем «окно» на одно обращение вправо и снова определим непустые прямоугольники; и так далее для всего профиля обращений. В результате мы получим «покрытие» – последовательность непустых прямоугольников, в каждом из которых содержится хотя бы по одному обращению, т.е. по одной точке профиля.&lt;br /&gt;
&lt;br /&gt;
Далее для каждого «окна» посчитаем число таких непустых прямоугольников (обозначим это число как rects), в результате чего получим последовательность положительных натуральных чисел. Затем посчитаем среднее значение для данной последовательности. Полученное значение назовем оценкой локальности на основе метода покрытий и будем обозначать cvg.&lt;br /&gt;
&lt;br /&gt;
Значение K было решено выбрать равным 64 байт, поскольку это соответствует длине кэш-строки, а в пределах одной кэш-строки пространственная локальность заведомо достаточно хорошая. При этом если запрошено одно значение, то в кэш-память подтянется вся строка из 64 байт, то есть все данные, соответствующие определенному прямоугольнику.&lt;br /&gt;
&lt;br /&gt;
Оптимальное значение N для разных программ может существенно отличаться, но для выполнения корректного сравнения оценка было решено выбрать единственное значение N. Было проведено сравнение результатов для различных значений N, и в результате эмпирическим путем было получено, что наилучшие результаты достигаются при N=512.&lt;br /&gt;
&lt;br /&gt;
=== Параллельная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Параллельная сложность&#039;&#039;&#039; (parallel complexity) алгоритма - количество основных вычислительных шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых ресурсов (процессоров, функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической [[#Ярусно-параллельная форма графа алгоритма|ярусно-параллельной формы]].&lt;br /&gt;
&lt;br /&gt;
=== Параметры запуска ===&lt;br /&gt;
&#039;&#039;&#039;Параметры запуска&#039;&#039;&#039; (startup parameters) параллельной программы - параметры, оказывающие влияние на работу параллельной программы, но не влияющие на реализацию алгоритма работы программы (например: размер задачи, число процессов, размер блока, число процессов на узел и т.п.) &lt;br /&gt;
Параметры запуска по типу можно разделить на:&lt;br /&gt;
# Аппаратные - относящиеся к параметрам аппаратуры.&lt;br /&gt;
# Системные - относящиеся к операционной системе, используемым библиотекам и системным приложениям и их настройкам.&lt;br /&gt;
# Программные - влияющие на логику работы программы или вычислительную сложность задачи, различные параметры, предусмотренные разработчиком.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пиковая производительность ===&lt;br /&gt;
&#039;&#039;&#039;Пиковая производительность&#039;&#039;&#039; (peak performance) &amp;lt;math&amp;gt;R_{peak}&amp;lt;/math&amp;gt; — теоретический предел [[#Производительность|производительности]] для данного компьютера. Пиковая производительность компьютера вычисляется как сумма пиковых производительностей всех входящих в него вычислительных устройств (процессоров, ускорителей и т.д.). Под пиковой производительностью каждого из вычислительных устройств понимают количество операций в секунду, которые он смог бы теоретически выполнять при полной загрузке всех своих компонент. Надо понимать, что пиковая производительность не только суперкомпьютера, но и, например, любого отдельно взятого процессора является величиной сугубо теоретической, недостижимой на практике.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Последовательная сложность&#039;&#039;&#039; (serial complexity) алгоритма - число операций, которые нужно выполнить при его последовательном исполнении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пространственная локальность ===&lt;br /&gt;
&#039;&#039;&#039;Пространственная локальность&#039;&#039;&#039; (spatial locality) отражает среднее расстояние между несколькими последовательными обращениями в память.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Производительность ===&lt;br /&gt;
&#039;&#039;&#039;Производительность&#039;&#039;&#039; (performance) &amp;lt;math&amp;gt;R=Op/t&amp;lt;/math&amp;gt; определяется количеством операций &amp;lt;math&amp;gt;Op&amp;lt;/math&amp;gt;, производимых данным компьютером в единицу времени. Для высокопроизводительных вычислений в расчёт обычно берут количество арифметических операций в секунду над вещественными данными, представленными в форме с плавающей точкой. Эта величина называется Flop/s (от английского Floating point operations per second).&lt;br /&gt;
&lt;br /&gt;
Поскольку современные суперкомпьютеры производят очень много таких операций в секунду, их производительность измеряется кратными величинами, такими как GFlop/s (&amp;lt;math&amp;gt;10^9&amp;lt;/math&amp;gt; операций в секунду), TFlop/s (&amp;lt;math&amp;gt;10^{12}&amp;lt;/math&amp;gt;), PFlop/s (&amp;lt;math&amp;gt;10^{15}&amp;lt;/math&amp;gt;), EFlop/s (&amp;lt;math&amp;gt;10^{18}&amp;lt;/math&amp;gt;). Производительность мощнейших современных суперкомпьютеров уже измеряется в EFlop/s, идёт обсуждение построения систем зеттафлопсного (порядка &amp;lt;math&amp;gt;10^{21}&amp;lt;/math&amp;gt; операций в секунду) уровня производительности.&lt;br /&gt;
&lt;br /&gt;
=== Профиль обращений в память ===&lt;br /&gt;
&#039;&#039;&#039;Профиль обращений в память&#039;&#039;&#039; (memory access profile) - последовательность выполняемых в программе обращений к данным в памяти, расположенных в том порядке, в котором обращения происходят в программе.&lt;br /&gt;
&lt;br /&gt;
Обозначим профиль обращений A = {A&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,A&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,…,A&amp;lt;sub&amp;gt;N&amp;lt;/sub&amp;gt;}, где N – общее число всех обращений при выполнении программы. Номер i элемента A&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; в профиле указывает, каким по счету является данное обращение от начала выполнения программы. Любой элемент А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; будем называть элементом профиля. Запись А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; означает, что данный элемент имеет i-й порядковый номер; данная запись не содержит никакой информации о том, к какой переменной в программе происходит данное обращение.&lt;br /&gt;
&lt;br /&gt;
На данный момент рассматриваются в основном обращения к массивам, поскольку они являются самыми распространенными структурами данных. Каждое обращение представлено в профиле некоторым числом. Таким образом, профиль обращений представляет собой последовательность чисел, которыми могут являться: 1) индексы элементов массива (если профиль строится только для одного массива); 2) виртуальные адреса, к которым происходят обращения; 3) физические адреса. Естественно, в рамках одного профиля используются числа только одного типа.&lt;br /&gt;
&lt;br /&gt;
Подобные профили обращений содержат огромное количество полезной информации о работе программы с памятью. Интересным средством анализа профилей является изучение их визуального представления. Пример визуализации профиля приведен на рис. 2. Ось абсцисс — порядковый номер обращения в память, т. е. чем больше номер, тем позже произошло данное обращение. По оси ординат отложен виртуальный адрес памяти, к которому произошло обращение. Каждая точка — это отдельное обращение в память. &lt;br /&gt;
&lt;br /&gt;
[[file:locality_profile.png|thumb|center|500px|Рисунок 2. Визуализация профиля обращений в память]]&lt;br /&gt;
&lt;br /&gt;
Подобные графики сами по себе могут предоставить интересную информацию о поведении программы. Выделенная на рисунке область 1 (и остальные, аналогичные ей области), скорее всего, обладает хорошей пространственной и временно́й локальностью. Хорошей пространственной — потому что используются только соседние по памяти данные; хорошей временно́й — поскольку повторные обращения к этим данным происходят часто. Область 2 также обладает хорошей пространственной локальностью, поскольку соседние обращения происходят к соседним элементам, однако плохой временно́й локальностью, поскольку повторных обращений к данным просто нет.&lt;br /&gt;
&lt;br /&gt;
Помимо получения данных о локальности, исследование визуализации профилей обращений в память является хорошим средством для понимания и определения шаблонов обращений.&lt;br /&gt;
&lt;br /&gt;
Подобный анализ на основе визуализации профиля обращений помогает понять общее поведение программы, однако он не может дать точной количественной информации о взаимодействии программ с памятью. Для этих целей разрабатываются оценки локальности, такие как [[#Оценка daps|daps]] и [[#Оценка cvg|cvg]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Реальная производительность ===&lt;br /&gt;
&#039;&#039;&#039;Реальная производительность&#039;&#039;&#039; (real performance) &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; — [[#Производительность|производительность]] данного компьютера на конкретном приложении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Сильная масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Сильная масштабируемость&#039;&#039;&#039; (strong scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи (&amp;lt;math&amp;gt;W=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скошенный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Скошенный параллелизм&#039;&#039;&#039; (skewed parallelism) - параллелизм в пространстве итераций, определяемый поверхностями уровней разверток. Ряд исследователей этим термином пользуется только для случая, когда параллелизм не является [[#Координатный паралеллизм|координатным]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Слабая масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Слабая масштабируемость&#039;&#039;&#039; (weak scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи в пересчёте на один процессор (&amp;lt;math&amp;gt;W/p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Степень исхода ===&lt;br /&gt;
&#039;&#039;&#039;Степень исхода&#039;&#039;&#039; (degree of a vertex) вершины информационного графа - количество исходящих из данной вершины информационных дуг.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Суперлинейное ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Суперлинейное ускорение&#039;&#039;&#039; (super linear speedup) или &#039;&#039;&#039;сверхлинейное ускорение&#039;&#039;&#039; программы - это [[#Ускорение|ускорение]], превосходящие число используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Чаще всего объясняется эффектом от использования кэш-памяти.&lt;br /&gt;
&lt;br /&gt;
=== Суперскалярность ===&lt;br /&gt;
&#039;&#039;&#039;Суперскалярность&#039;&#039;&#039; — архитектура вычислительного ядра, позволяющая загружать работой множество исполнительных блоков. Планирование исполнения команд является динамическим и осуществляется самим ядром. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Суперскалярность Суперскалярность]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Ускорение&#039;&#039;&#039; (speedup) работы программы &amp;lt;math&amp;gt;S = T_1/T_p&amp;lt;/math&amp;gt; - отношение времени работы некоторой программы на одном процессоре &amp;lt;math&amp;gt;T_1&amp;lt;/math&amp;gt; ко времени работы распараллеленной программы при использовании &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; процессоров &amp;lt;math&amp;gt;T_p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&#039;&#039;&#039;Устойчивость&#039;&#039;&#039; (stability) алгоритма - свойство алгоритма не увеличивать или увеличивать в незначительной степени погрешности, допущенной в начальных данных или допускаемой при вычислениях.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное возмущение ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное возмущение&#039;&#039;&#039; (equivalent perturbation) алгоритма - одна из характеристик влияния ошибок округления промежуточных операций на отклонение решения, получаемого алгоритмом, от настоящего решения задачи. Выражается косвенно: влияние ошибок на ответ считается таким же, как если бы данные были заданы с ошибкой, выражаемой эквивалентным возмущением, но задача с такими данными была бы решена точно.&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное преобразование ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное преобразование&#039;&#039;&#039; (equivalent transformaion) программы - такое преобразование, при котором в точности сохраняется результат выполнения программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность распараллеливания ===&lt;br /&gt;
&#039;&#039;&#039;Эффективность распараллеливания&#039;&#039;&#039; (parallel efficiency) &amp;lt;math&amp;gt;E = S/p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; - полученное [[#Ускорение|ускорение]] работы программы, а &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число используемых процессоров) определяет среднюю долю времени выполнения параллельного алгоритма, в течение которого процессоры реально используются для решения задачи. Получение большого ускорения за счёт использования большого числа процессоров зачастую приводит к снижению эффективности.&lt;br /&gt;
&lt;br /&gt;
Если не брать в расчёт эффект [[#Суперлинейное ускорение|суперлинейного ускорения]], то ускорение выполнения программы не превосходит числа используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;, а значит, эффективность распараллеливания не превосходит единицы. Чем ближе этот показатель к единице, тем лучше для пользователя, поскольку говорит о меньшем количестве накладных расходов, а значит, о лучшем качестве распараллеливания программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность реализации ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эффективность реализации&#039;&#039;&#039; (implementation efficiency) программы &amp;lt;math&amp;gt;R_{max}/R_{peak}&amp;lt;/math&amp;gt; определяется как отношение [[#Реальная производительность|реальной производительности]] &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; к [[#Пиковая производительность|пиковой производительности]] &amp;lt;math&amp;gt;R_{peak}&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;
&#039;&#039;&#039;Ярусно-параллельная форма (ЯПФ)&#039;&#039;&#039; (parallel form) - это представление графа алгоритма, в котором:&lt;br /&gt;
* все вершины разбиты на перенумерованные подмножества ярусов;&lt;br /&gt;
* начальная вершина каждой дуги расположена на ярусе с номером меньшим, чем номер яруса конечной вершины;&lt;br /&gt;
* между вершинами, расположенными на одном ярусе, не может быть дуг.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Высота&#039;&#039; ЯПФ - это число ярусов.&lt;br /&gt;
Ширина яруса - число вершин, расположенных на ярусе.&lt;br /&gt;
&#039;&#039;Ширина&#039;&#039; ЯПФ - это максимальная ширина ярусов в ЯПФ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Канонической ярусно-параллельной формой&#039;&#039;&#039; называется ЯПФ, высота которой на единицу больше длины критического пути, а все входные вершины расположены на первом ярусе. Для заданного графа его каноническая ЯПФ единственна. Высота канонической ЯПФ соответствует [[#Параллельная сложность|параллельной сложности]] алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Ярусно-параллельная_форма_графа Ярусно-параллельная форма графа]&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Критический_путь_графа Критический путь графа]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[En:Glossary]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Algowiki:Справка]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=30386</id>
		<title>Глоссарий</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=30386"/>
		<updated>2026-01-16T09:50:26Z</updated>

		<summary type="html">&lt;p&gt;ASA: /* Вычислительная сложность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Временна́я локальность ===&lt;br /&gt;
&#039;&#039;&#039;Временная локальность&#039;&#039;&#039; (temporal locality) показывает среднее число обращений по одному адресу в память за время исполнения всей программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная мощность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная мощность&#039;&#039;&#039; (computational power) алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная сложность&#039;&#039;&#039; (computational complexity) задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; - количество основных вычислительных шагов лучшего последовательного алгоритма, необходимых для решения задачи на одном процессоре. Вычислительная сложность обычно является некоторой функцией от размера входных данных рассматриваемого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительное ядро&#039;&#039;&#039; (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Граф алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Граф алгоритма&#039;&#039;&#039; (algorithm graph) - это ориентированный ациклический мультиграф, вершины которого соответствуют операциям алгоритма, а дуги - передаче данных между ними. Вершины графа алгоритма могут соединяться несколькими дугами, в частности когда в качестве разных аргументов одной и той же операции используется одна и та же величина. Граф алгоритма почти всегда является параметризованным графом. В частности, его вид часто зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма используется как удобное представление алгоритма при исследовании его структуры, ресурса параллелизма, а также других свойств. Его можно рассматривать как параметризованную информационную историю. Он сохраняет её информативность, при этом обладая компактностью за счёт параметризации. Разработана методика построения графа алгоритма по исходному тексту программ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также: [https://ru.wikipedia.org/wiki/Граф_алгоритма Граф алгоритма]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&#039;&#039;&#039;Детерминированность&#039;&#039;&#039; (determinacy) алгоритма - постоянство структуры вычислительного процесса. Алгоритм выдаёт уникальный и предопределённый результат для заданных входных данных.&lt;br /&gt;
&lt;br /&gt;
=== Избыточные вычисления ===&lt;br /&gt;
&#039;&#039;&#039;Избыточные вычисления&#039;&#039;&#039; (redundant computation) - понятие, которое используют для обозначения разных явлений в параллельных вычислениях. &lt;br /&gt;
* В понимании графовой модели вычислений это такие операции, результаты которых нигде не будут использованы. Такие операции появляются в результате ошибок программирования и подлежат удалению из алгоритма. &lt;br /&gt;
* Распространено также понимание термина как вычисления, которые &#039;&#039;выполняются более одного раза&#039;&#039; или на более чем одном процессоре. Избыточные вычисления могут использоваться либо в многопроцессорных системах, чтобы минимизировать обмены, либо при недостаточном объеме памяти для хранения всех вычисленных значений. &lt;br /&gt;
* Кроме этого, избыточными вычислениями можно назвать те операции, которые появляются при замене последовательного алгоритма на специальный параллельный. У последнего алгоритма больше операций, но меньше длина критического пути графа, этим и обосновывается замена алгоритма. В таком случае реальное ускорение параллельного алгоритма следует считать не в сравнении с однопроцессорной реализацией его самого, а в сравнении с реализацией последовательного алгоритма. В нашей открытой энциклопедии свойств алгоритмов именно последнее толкование термина применяется в категории [[http://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D1%81_%D0%B8%D0%B7%D0%B1%D1%8B%D1%82%D0%BE%D1%87%D0%BD%D1%8B%D0%BC%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8 Алгоритмы с избыточными вычислениями]].&lt;br /&gt;
&lt;br /&gt;
=== Конечный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Конечный параллелизм&#039;&#039;&#039; (finite parallelism) - параллелизм, определяемый информационной независимостью некоторых фрагментов в тексте программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Координатный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Координатный параллелизм&#039;&#039;&#039; (coordinate parallelism) - частный случай [[#Скошенный паралеллизм|скошенного параллелизма]], определяемый циклами ParDO, при котором информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность (обращений в память) ===&lt;br /&gt;
&#039;&#039;&#039;Локальность (обращений в память)&#039;&#039;&#039; (locality) - общее предположение о свойстве работы программ с данными. Заключается в том, что при обращении к некоторым данным велика вероятность, что в скором времени произойдет повторное обращение к тем же или расположенным рядом данным. В частности, на основе данного предположения построена работа кэш-памяти. Различают [[#Локальность команд|локальность команд]] и [[#Локальность использования данных|локальность использования данных]], а также [[#Пространственная локальность|пространственную]] и [[#Временна́я локальность|временну́ю]] локальность.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность вычислений ===&lt;br /&gt;
&#039;&#039;&#039;Локальность вычислений&#039;&#039;&#039; (computation locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - команды, из которых состоят программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность использования данных ===&lt;br /&gt;
&#039;&#039;&#039;Локальность использования данных&#039;&#039;&#039; (data locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - все данные, с которыми оперируют программы во время выполнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Массовый параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Массовый параллелизм&#039;&#039;&#039; (mass parallelism) - параллелизм, определяемый информационной независимостью итераций циклов программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость&#039;&#039;&#039; (scalability) - способность системы увеличивать свою [[#Производительность|производительность]] при добавлении ресурсов (обычно аппаратных). Система называется масштабируемой, если она способна увеличивать производительность пропорционально дополнительным ресурсам. Масштабируемость можно оценить через отношение прироста производительности системы к приросту используемых ей ресурсов. Чем ближе это отношение к единице, тем масштабируемость лучше.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость параллельной программы ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость параллельной программы&#039;&#039;&#039; (scalability of parallel program) определяется относительно конкретного компьютера и показывает, как изменяются динамические характеристики данной программы в зависимости от её [[#Параметры запуска|параметров запуска]].&lt;br /&gt;
&lt;br /&gt;
Наиболее часто рассматриваемые разновидности масштабируемости параллельных программ: [[#Сильная масштабируемость|сильная масштабируемость]], [[#Масштабируемость вширь|масштабируемость вширь]], [[#Слабая масштабируемость|слабая масштабируемость]].&lt;br /&gt;
&lt;br /&gt;
Если при одновременном увеличении числа процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; и [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; [[#Эффективность распараллеливания|эффективность распараллеливания]] &amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; остаётся прежней, то данную программу на данном компьютере можно считать масштабируемой.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость вширь ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость вширь&#039;&#039;&#039; (wide scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; при фиксированном числе процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка daps ===&lt;br /&gt;
&#039;&#039;&#039;Оценка daps&#039;&#039;&#039; (daps estimation) - предлагаемая оценка производительности работы с памятью в программе, равна числу выполненных обращений в память в секунду. Построена по аналогии с распространенной оценкой производительности программ — flop/s (floating point operations per second), которая оценивает число операций с плавающей запятой в секунду. Оценка flop/s показывает производительность всей программы с точки зрения производимых вычислений; в то время как daps оценивает производительность программы с точки зрения работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Данная оценка является машинно-зависимой — она вычисляется на основе данных аппаратных датчиков. Служит для проверки точности результатов разрабатываемых нами машинно-независимых оценок локальности, таких как [[#Оценка cvg|cvg]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка cvg ===&lt;br /&gt;
&#039;&#039;&#039;Оценка cvg&#039;&#039;&#039; (cvg estimation) - предлагаемая машинно-независимая оценка локальности обращений в памяти в программе. Рассмотрим первые N обращений в потоке («окно»), и затем разобьем ось ординат (виртуальный адрес обращений) на отрезки длины K – [X .. X+K],  [X+K .. X+2K], …, [Y-K .. Y], где [X, Y] - диапазон выделенной под рассматриваемые массивы виртуальной памяти. Таким образом, область построения профиля делится на прямоугольники размером KxN. &lt;br /&gt;
&lt;br /&gt;
Физический смысл такого прямоугольника (при правильно подобранных значениях K и N) заключается в том, что любая последовательность точек, попавших в один прямоугольник, всегда обладает хорошей как пространственной, так и временно́й локальностью. Действительно, при достаточно малом значении K в прямоугольник попадает небольшой локальный фрагмент виртуальной памяти, а, значит, соседние обращения по памяти в любом случае будут расположены близко друг относительно друга. А временна́я локальность внутри прямоугольника не может быть больше N, поэтому при достаточно малом N можно обеспечить и хорошую временну́ю локальность. Однако не имеет смысла брать слишком малые значения для K и N, поскольку в этом случае теряется полезная информация о хорошей локальности не попавшего в прямоугольник фрагмента профиля.&lt;br /&gt;
&lt;br /&gt;
Выделим те прямоугольники, в которые попадает хотя бы одно обращение. Чем меньше таких прямоугольников – тем больше точек попало в одни и те же прямоугольники, тем в общем случае лучше локальность. Пример разбиения профиля на прямоугольники приведен на рис. 1. Здесь для иллюстрации выделено три «окна», в каждом по 6 точек. В первом «окне» всего 2 непустых прямоугольника и самая хорошая локальность их трех вариантов. Во втором «окне» задействованы все 4 прямоугольника, при этом в каждый попало лишь по 1-2 обращения. Третье «окно» включает 3 непустых прямоугольника, и в этом варианте локальность лучше, чем у второго «окна», но хуже, чем у первого.&lt;br /&gt;
&lt;br /&gt;
[[file:cvg.png|thumb|center|500px|Рисунок 1. Пример разбиения профиля на прямоугольники]]&lt;br /&gt;
&lt;br /&gt;
Теперь сдвинем «окно» на одно обращение вправо и снова определим непустые прямоугольники; и так далее для всего профиля обращений. В результате мы получим «покрытие» – последовательность непустых прямоугольников, в каждом из которых содержится хотя бы по одному обращению, т.е. по одной точке профиля.&lt;br /&gt;
&lt;br /&gt;
Далее для каждого «окна» посчитаем число таких непустых прямоугольников (обозначим это число как rects), в результате чего получим последовательность положительных натуральных чисел. Затем посчитаем среднее значение для данной последовательности. Полученное значение назовем оценкой локальности на основе метода покрытий и будем обозначать cvg.&lt;br /&gt;
&lt;br /&gt;
Значение K было решено выбрать равным 64 байт, поскольку это соответствует длине кэш-строки, а в пределах одной кэш-строки пространственная локальность заведомо достаточно хорошая. При этом если запрошено одно значение, то в кэш-память подтянется вся строка из 64 байт, то есть все данные, соответствующие определенному прямоугольнику.&lt;br /&gt;
&lt;br /&gt;
Оптимальное значение N для разных программ может существенно отличаться, но для выполнения корректного сравнения оценка было решено выбрать единственное значение N. Было проведено сравнение результатов для различных значений N, и в результате эмпирическим путем было получено, что наилучшие результаты достигаются при N=512.&lt;br /&gt;
&lt;br /&gt;
=== Параллельная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Параллельная сложность&#039;&#039;&#039; (parallel complexity) алгоритма - число шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых процессоров (функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической [[#Ярусно-параллельная форма графа алгоритма|ярусно-параллельной формы]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Параметры запуска ===&lt;br /&gt;
&#039;&#039;&#039;Параметры запуска&#039;&#039;&#039; (startup parameters) параллельной программы - параметры, оказывающие влияние на работу параллельной программы, но не влияющие на реализацию алгоритма работы программы (например: размер задачи, число процессов, размер блока, число процессов на узел и т.п.) &lt;br /&gt;
Параметры запуска по типу можно разделить на:&lt;br /&gt;
# Аппаратные - относящиеся к параметрам аппаратуры.&lt;br /&gt;
# Системные - относящиеся к операционной системе, используемым библиотекам и системным приложениям и их настройкам.&lt;br /&gt;
# Программные - влияющие на логику работы программы или вычислительную сложность задачи, различные параметры, предусмотренные разработчиком.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пиковая производительность ===&lt;br /&gt;
&#039;&#039;&#039;Пиковая производительность&#039;&#039;&#039; (peak performance) &amp;lt;math&amp;gt;R_{peak}&amp;lt;/math&amp;gt; — теоретический предел [[#Производительность|производительности]] для данного компьютера. Пиковая производительность компьютера вычисляется как сумма пиковых производительностей всех входящих в него вычислительных устройств (процессоров, ускорителей и т.д.). Под пиковой производительностью каждого из вычислительных устройств понимают количество операций в секунду, которые он смог бы теоретически выполнять при полной загрузке всех своих компонент. Надо понимать, что пиковая производительность не только суперкомпьютера, но и, например, любого отдельно взятого процессора является величиной сугубо теоретической, недостижимой на практике.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Последовательная сложность&#039;&#039;&#039; (serial complexity) алгоритма - число операций, которые нужно выполнить при его последовательном исполнении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пространственная локальность ===&lt;br /&gt;
&#039;&#039;&#039;Пространственная локальность&#039;&#039;&#039; (spatial locality) отражает среднее расстояние между несколькими последовательными обращениями в память.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Производительность ===&lt;br /&gt;
&#039;&#039;&#039;Производительность&#039;&#039;&#039; (performance) &amp;lt;math&amp;gt;R=Op/t&amp;lt;/math&amp;gt; определяется количеством операций &amp;lt;math&amp;gt;Op&amp;lt;/math&amp;gt;, производимых данным компьютером в единицу времени. Для высокопроизводительных вычислений в расчёт обычно берут количество арифметических операций в секунду над вещественными данными, представленными в форме с плавающей точкой. Эта величина называется Flop/s (от английского Floating point operations per second).&lt;br /&gt;
&lt;br /&gt;
Поскольку современные суперкомпьютеры производят очень много таких операций в секунду, их производительность измеряется кратными величинами, такими как GFlop/s (&amp;lt;math&amp;gt;10^9&amp;lt;/math&amp;gt; операций в секунду), TFlop/s (&amp;lt;math&amp;gt;10^{12}&amp;lt;/math&amp;gt;), PFlop/s (&amp;lt;math&amp;gt;10^{15}&amp;lt;/math&amp;gt;), EFlop/s (&amp;lt;math&amp;gt;10^{18}&amp;lt;/math&amp;gt;). Производительность мощнейших современных суперкомпьютеров уже измеряется в EFlop/s, идёт обсуждение построения систем зеттафлопсного (порядка &amp;lt;math&amp;gt;10^{21}&amp;lt;/math&amp;gt; операций в секунду) уровня производительности.&lt;br /&gt;
&lt;br /&gt;
=== Профиль обращений в память ===&lt;br /&gt;
&#039;&#039;&#039;Профиль обращений в память&#039;&#039;&#039; (memory access profile) - последовательность выполняемых в программе обращений к данным в памяти, расположенных в том порядке, в котором обращения происходят в программе.&lt;br /&gt;
&lt;br /&gt;
Обозначим профиль обращений A = {A&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,A&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,…,A&amp;lt;sub&amp;gt;N&amp;lt;/sub&amp;gt;}, где N – общее число всех обращений при выполнении программы. Номер i элемента A&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; в профиле указывает, каким по счету является данное обращение от начала выполнения программы. Любой элемент А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; будем называть элементом профиля. Запись А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; означает, что данный элемент имеет i-й порядковый номер; данная запись не содержит никакой информации о том, к какой переменной в программе происходит данное обращение.&lt;br /&gt;
&lt;br /&gt;
На данный момент рассматриваются в основном обращения к массивам, поскольку они являются самыми распространенными структурами данных. Каждое обращение представлено в профиле некоторым числом. Таким образом, профиль обращений представляет собой последовательность чисел, которыми могут являться: 1) индексы элементов массива (если профиль строится только для одного массива); 2) виртуальные адреса, к которым происходят обращения; 3) физические адреса. Естественно, в рамках одного профиля используются числа только одного типа.&lt;br /&gt;
&lt;br /&gt;
Подобные профили обращений содержат огромное количество полезной информации о работе программы с памятью. Интересным средством анализа профилей является изучение их визуального представления. Пример визуализации профиля приведен на рис. 2. Ось абсцисс — порядковый номер обращения в память, т. е. чем больше номер, тем позже произошло данное обращение. По оси ординат отложен виртуальный адрес памяти, к которому произошло обращение. Каждая точка — это отдельное обращение в память. &lt;br /&gt;
&lt;br /&gt;
[[file:locality_profile.png|thumb|center|500px|Рисунок 2. Визуализация профиля обращений в память]]&lt;br /&gt;
&lt;br /&gt;
Подобные графики сами по себе могут предоставить интересную информацию о поведении программы. Выделенная на рисунке область 1 (и остальные, аналогичные ей области), скорее всего, обладает хорошей пространственной и временно́й локальностью. Хорошей пространственной — потому что используются только соседние по памяти данные; хорошей временно́й — поскольку повторные обращения к этим данным происходят часто. Область 2 также обладает хорошей пространственной локальностью, поскольку соседние обращения происходят к соседним элементам, однако плохой временно́й локальностью, поскольку повторных обращений к данным просто нет.&lt;br /&gt;
&lt;br /&gt;
Помимо получения данных о локальности, исследование визуализации профилей обращений в память является хорошим средством для понимания и определения шаблонов обращений.&lt;br /&gt;
&lt;br /&gt;
Подобный анализ на основе визуализации профиля обращений помогает понять общее поведение программы, однако он не может дать точной количественной информации о взаимодействии программ с памятью. Для этих целей разрабатываются оценки локальности, такие как [[#Оценка daps|daps]] и [[#Оценка cvg|cvg]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Реальная производительность ===&lt;br /&gt;
&#039;&#039;&#039;Реальная производительность&#039;&#039;&#039; (real performance) &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; — [[#Производительность|производительность]] данного компьютера на конкретном приложении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Сильная масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Сильная масштабируемость&#039;&#039;&#039; (strong scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи (&amp;lt;math&amp;gt;W=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скошенный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Скошенный параллелизм&#039;&#039;&#039; (skewed parallelism) - параллелизм в пространстве итераций, определяемый поверхностями уровней разверток. Ряд исследователей этим термином пользуется только для случая, когда параллелизм не является [[#Координатный паралеллизм|координатным]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Слабая масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Слабая масштабируемость&#039;&#039;&#039; (weak scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи в пересчёте на один процессор (&amp;lt;math&amp;gt;W/p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Степень исхода ===&lt;br /&gt;
&#039;&#039;&#039;Степень исхода&#039;&#039;&#039; (degree of a vertex) вершины информационного графа - количество исходящих из данной вершины информационных дуг.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Суперлинейное ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Суперлинейное ускорение&#039;&#039;&#039; (super linear speedup) или &#039;&#039;&#039;сверхлинейное ускорение&#039;&#039;&#039; программы - это [[#Ускорение|ускорение]], превосходящие число используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Чаще всего объясняется эффектом от использования кэш-памяти.&lt;br /&gt;
&lt;br /&gt;
=== Суперскалярность ===&lt;br /&gt;
&#039;&#039;&#039;Суперскалярность&#039;&#039;&#039; — архитектура вычислительного ядра, позволяющая загружать работой множество исполнительных блоков. Планирование исполнения команд является динамическим и осуществляется самим ядром. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Суперскалярность Суперскалярность]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Ускорение&#039;&#039;&#039; (speedup) работы программы &amp;lt;math&amp;gt;S = T_1/T_p&amp;lt;/math&amp;gt; - отношение времени работы некоторой программы на одном процессоре &amp;lt;math&amp;gt;T_1&amp;lt;/math&amp;gt; ко времени работы распараллеленной программы при использовании &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; процессоров &amp;lt;math&amp;gt;T_p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&#039;&#039;&#039;Устойчивость&#039;&#039;&#039; (stability) алгоритма - свойство алгоритма не увеличивать или увеличивать в незначительной степени погрешности, допущенной в начальных данных или допускаемой при вычислениях.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное возмущение ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное возмущение&#039;&#039;&#039; (equivalent perturbation) алгоритма - одна из характеристик влияния ошибок округления промежуточных операций на отклонение решения, получаемого алгоритмом, от настоящего решения задачи. Выражается косвенно: влияние ошибок на ответ считается таким же, как если бы данные были заданы с ошибкой, выражаемой эквивалентным возмущением, но задача с такими данными была бы решена точно.&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное преобразование ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное преобразование&#039;&#039;&#039; (equivalent transformaion) программы - такое преобразование, при котором в точности сохраняется результат выполнения программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность распараллеливания ===&lt;br /&gt;
&#039;&#039;&#039;Эффективность распараллеливания&#039;&#039;&#039; (parallel efficiency) &amp;lt;math&amp;gt;E = S/p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; - полученное [[#Ускорение|ускорение]] работы программы, а &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число используемых процессоров) определяет среднюю долю времени выполнения параллельного алгоритма, в течение которого процессоры реально используются для решения задачи. Получение большого ускорения за счёт использования большого числа процессоров зачастую приводит к снижению эффективности.&lt;br /&gt;
&lt;br /&gt;
Если не брать в расчёт эффект [[#Суперлинейное ускорение|суперлинейного ускорения]], то ускорение выполнения программы не превосходит числа используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;, а значит, эффективность распараллеливания не превосходит единицы. Чем ближе этот показатель к единице, тем лучше для пользователя, поскольку говорит о меньшем количестве накладных расходов, а значит, о лучшем качестве распараллеливания программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность реализации ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эффективность реализации&#039;&#039;&#039; (implementation efficiency) программы &amp;lt;math&amp;gt;R_{max}/R_{peak}&amp;lt;/math&amp;gt; определяется как отношение [[#Реальная производительность|реальной производительности]] &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; к [[#Пиковая производительность|пиковой производительности]] &amp;lt;math&amp;gt;R_{peak}&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;
&#039;&#039;&#039;Ярусно-параллельная форма (ЯПФ)&#039;&#039;&#039; (parallel form) - это представление графа алгоритма, в котором:&lt;br /&gt;
* все вершины разбиты на перенумерованные подмножества ярусов;&lt;br /&gt;
* начальная вершина каждой дуги расположена на ярусе с номером меньшим, чем номер яруса конечной вершины;&lt;br /&gt;
* между вершинами, расположенными на одном ярусе, не может быть дуг.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Высота&#039;&#039; ЯПФ - это число ярусов.&lt;br /&gt;
Ширина яруса - число вершин, расположенных на ярусе.&lt;br /&gt;
&#039;&#039;Ширина&#039;&#039; ЯПФ - это максимальная ширина ярусов в ЯПФ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Канонической ярусно-параллельной формой&#039;&#039;&#039; называется ЯПФ, высота которой на единицу больше длины критического пути, а все входные вершины расположены на первом ярусе. Для заданного графа его каноническая ЯПФ единственна. Высота канонической ЯПФ соответствует [[#Параллельная сложность|параллельной сложности]] алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Ярусно-параллельная_форма_графа Ярусно-параллельная форма графа]&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Критический_путь_графа Критический путь графа]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[En:Glossary]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Algowiki:Справка]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Picture1_1.png&amp;diff=30070</id>
		<title>Файл:Picture1 1.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Picture1_1.png&amp;diff=30070"/>
		<updated>2025-11-25T07:18:01Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;rtew&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%85%D0%B5%D0%BC%D0%B0_%D0%93%D0%BE%D1%80%D0%BD%D0%B5%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29731</id>
		<title>Схема Горнера, вещественная версия, последовательный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%85%D0%B5%D0%BC%D0%B0_%D0%93%D0%BE%D1%80%D0%BD%D0%B5%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29731"/>
		<updated>2025-03-14T12:10:04Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Схема Горнера для деления многочлена n-й степени на приведённый двучлен&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;1&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;n+1&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
==== Решаемая задача ====&lt;br /&gt;
&lt;br /&gt;
Схема Горнера&amp;lt;ref&amp;gt;Н.Я. Виленкин, Р.С. Гутер, С.И. Шварцбурд, Б.В. Овчинский, В.Г. Ашкинузе. Алгебра. Учебное пособие для 9-10 классов средних школ с математической специализацией. М.: Просвещение, 1972&amp;lt;/ref&amp;gt; решает задачу деления многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; с известными коэффициентами на двучлен &amp;lt;math&amp;gt;x - \alpha&amp;lt;/math&amp;gt;. В качестве результатов выступают коэффициенты многочлена &amp;lt;math&amp;gt;Q_{n - 1}(x)&amp;lt;/math&amp;gt; из соотношения&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;P_n(x) - P_n(\alpha) = (x - \alpha) Q_{n - 1}(x)&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
а также &amp;lt;math&amp;gt;P_n(\alpha)&amp;lt;/math&amp;gt; (значение многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
К сожалению, зачастую в учебной литературе схему Горнера сводят к вычислению значения многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Общая схема ====&lt;br /&gt;
&lt;br /&gt;
Фактически схема Горнера реализует «деление уголком» многочлена на двучлен &amp;lt;math&amp;gt;x - \alpha&amp;lt;/math&amp;gt;, с нахождением остатка, который, по теореме Безу, равен значению многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt; чисел &amp;lt;math&amp;gt;a_k&amp;lt;/math&amp;gt; и скаляр &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: одномерный массив &amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt; чисел &amp;lt;math&amp;gt;b_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Формулы метода с выводом: из соотношения &lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;P_n(x) - P_n(\alpha) = (x - \alpha) Q_{n - 1}(x)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
если записать оба многочлена в каноническом виде&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
P_n(x)       &amp;amp; = a_0 x^n+ a_1 x^{n - 1} + \dots + a_{n - 1} x + a_n, \\&lt;br /&gt;
Q_{n - 1}(x) &amp;amp; = b_0 x^{n - 1} + b_1 x^{n - 2} + \dots + b_{n - 2} x + b_{n - 1}&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и приписать «свободному» &amp;lt;math&amp;gt;b_n&amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt;P_n(\alpha)&amp;lt;/math&amp;gt;, то, при подстановке многочленов в каноническом виде в исходное соотношение и приравнивании коэффициентов равных степеней, в качестве решения получается&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
b_0 &amp;amp; = a_0, \\&lt;br /&gt;
b_k &amp;amp; = a_k + \alpha b_{k - 1}, \quad k = 1, \dots, n&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
что и является &#039;&#039;&#039;формулами схемы Горнера&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро схемы Горнера в последовательном варианте можно представить в качестве последовательного набора &amp;lt;math&amp;gt;n&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;
Формулы метода описаны выше. Последовательность исполнения — по возрастанию индекса &#039;&#039;k&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления схемы Горнера для многочлена степени &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, количество операций умножения равно количеству операций сложения и равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф алгоритма для &amp;lt;math&amp;gt;n = 9&amp;lt;/math&amp;gt;. Как видно, граф чисто последовательный. Ввод и вывод обозначен только для начального коэффициента и значения многочлена. Op - операция &amp;quot;умножить входное данное на скаляр и прибавить к другому данному&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[file:Basic sequental algorithm graph.png|center|thumb|800px|Рисунок 1. Схема Горнера: последовательная версия]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательный вариант вычисления схемы Горнера не имеет ресурсов параллелизма. Его ярусно-параллельная форма (ЯПФ) — единственна и совпадает с последовательным алгоритмом. Таким образом, в получившемся алгоритме высота параллельной формы будет равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения плюс &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций сложения. В таком виде алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по высоте параллельной формы. Ширина параллельной формы равна &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;, что даёт нам &#039;&#039;постоянную&#039;&#039; сложность по ширине параллельной формы.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; с номерами от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;), скаляр &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n + 2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: массив &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_k&amp;lt;/math&amp;gt; с номерами от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Объём выходных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;константой&#039;&#039; (1). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных даже на 1 больше, чем количество операций)&#039;&#039;. При этом алгоритм полностью детерминирован. Дуги информационного графа локальны. По устойчивости схема Горнера оптимальна для вычисления значения многочлена с известными коэффициентами.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
На Фортране схему Горнера можно записать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	b(0) = a(0)&lt;br /&gt;
	DO I = 1, N&lt;br /&gt;
		b(I) = a(I)+b(I-1)*alpha&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&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;b&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en: Horners method]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
[[Категория:Алгоритмы с низким уровнем параллелизма]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%85%D0%B5%D0%BC%D0%B0_%D0%93%D0%BE%D1%80%D0%BD%D0%B5%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29730</id>
		<title>Схема Горнера, вещественная версия, последовательный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%85%D0%B5%D0%BC%D0%B0_%D0%93%D0%BE%D1%80%D0%BD%D0%B5%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29730"/>
		<updated>2025-03-14T12:08:15Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Схема Горнера для деления многочлена n-й степени на приведённый двучлен&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;11n-16&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;n+2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n+1&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
==== Решаемая задача ====&lt;br /&gt;
&lt;br /&gt;
Схема Горнера&amp;lt;ref&amp;gt;Н.Я. Виленкин, Р.С. Гутер, С.И. Шварцбурд, Б.В. Овчинский, В.Г. Ашкинузе. Алгебра. Учебное пособие для 9-10 классов средних школ с математической специализацией. М.: Просвещение, 1972&amp;lt;/ref&amp;gt; решает задачу деления многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; с известными коэффициентами на двучлен &amp;lt;math&amp;gt;x - \alpha&amp;lt;/math&amp;gt;. В качестве результатов выступают коэффициенты многочлена &amp;lt;math&amp;gt;Q_{n - 1}(x)&amp;lt;/math&amp;gt; из соотношения&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;P_n(x) - P_n(\alpha) = (x - \alpha) Q_{n - 1}(x)&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
а также &amp;lt;math&amp;gt;P_n(\alpha)&amp;lt;/math&amp;gt; (значение многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
К сожалению, зачастую в учебной литературе схему Горнера сводят к вычислению значения многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Общая схема ====&lt;br /&gt;
&lt;br /&gt;
Фактически схема Горнера реализует «деление уголком» многочлена на двучлен &amp;lt;math&amp;gt;x - \alpha&amp;lt;/math&amp;gt;, с нахождением остатка, который, по теореме Безу, равен значению многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt; чисел &amp;lt;math&amp;gt;a_k&amp;lt;/math&amp;gt; и скаляр &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: одномерный массив &amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt; чисел &amp;lt;math&amp;gt;b_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Формулы метода с выводом: из соотношения &lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;P_n(x) - P_n(\alpha) = (x - \alpha) Q_{n - 1}(x)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
если записать оба многочлена в каноническом виде&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
P_n(x)       &amp;amp; = a_0 x^n+ a_1 x^{n - 1} + \dots + a_{n - 1} x + a_n, \\&lt;br /&gt;
Q_{n - 1}(x) &amp;amp; = b_0 x^{n - 1} + b_1 x^{n - 2} + \dots + b_{n - 2} x + b_{n - 1}&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и приписать «свободному» &amp;lt;math&amp;gt;b_n&amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt;P_n(\alpha)&amp;lt;/math&amp;gt;, то, при подстановке многочленов в каноническом виде в исходное соотношение и приравнивании коэффициентов равных степеней, в качестве решения получается&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
b_0 &amp;amp; = a_0, \\&lt;br /&gt;
b_k &amp;amp; = a_k + \alpha b_{k - 1}, \quad k = 1, \dots, n&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
что и является &#039;&#039;&#039;формулами схемы Горнера&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро схемы Горнера в последовательном варианте можно представить в качестве последовательного набора &amp;lt;math&amp;gt;n&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;
Формулы метода описаны выше. Последовательность исполнения — по возрастанию индекса &#039;&#039;k&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления схемы Горнера для многочлена степени &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, количество операций умножения равно количеству операций сложения и равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф алгоритма для &amp;lt;math&amp;gt;n = 9&amp;lt;/math&amp;gt;. Как видно, граф чисто последовательный. Ввод и вывод обозначен только для начального коэффициента и значения многочлена. Op - операция &amp;quot;умножить входное данное на скаляр и прибавить к другому данному&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[file:Basic sequental algorithm graph.png|center|thumb|800px|Рисунок 1. Схема Горнера: последовательная версия]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательный вариант вычисления схемы Горнера не имеет ресурсов параллелизма. Его ярусно-параллельная форма (ЯПФ) — единственна и совпадает с последовательным алгоритмом. Таким образом, в получившемся алгоритме высота параллельной формы будет равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения плюс &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций сложения. В таком виде алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по высоте параллельной формы. Ширина параллельной формы равна &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;, что даёт нам &#039;&#039;постоянную&#039;&#039; сложность по ширине параллельной формы.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; с номерами от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;), скаляр &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n + 2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: массив &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_k&amp;lt;/math&amp;gt; с номерами от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Объём выходных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;константой&#039;&#039; (1). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных даже на 1 больше, чем количество операций)&#039;&#039;. При этом алгоритм полностью детерминирован. Дуги информационного графа локальны. По устойчивости схема Горнера оптимальна для вычисления значения многочлена с известными коэффициентами.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
На Фортране схему Горнера можно записать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	b(0) = a(0)&lt;br /&gt;
	DO I = 1, N&lt;br /&gt;
		b(I) = a(I)+b(I-1)*alpha&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&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;b&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en: Horners method]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
[[Категория:Алгоритмы с низким уровнем параллелизма]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=29729</id>
		<title>Глоссарий</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=29729"/>
		<updated>2025-03-14T10:07:27Z</updated>

		<summary type="html">&lt;p&gt;ASA: /* Эквивалентное возмущение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Временна́я локальность ===&lt;br /&gt;
&#039;&#039;&#039;Временная локальность&#039;&#039;&#039; (temporal locality) показывает среднее число обращений по одному адресу в память за время исполнения всей программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная мощность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная мощность&#039;&#039;&#039; (computational power) алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная сложность&#039;&#039;&#039; (computational complexity) задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; - количество основных вычислительных шагов лучшего последовательного алгоритма, необходимых для решения задачи на одном процессоре. Вычислительная сложность обычно является некоторой функцией от размера входных данных программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительное ядро&#039;&#039;&#039; (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Граф алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Граф алгоритма&#039;&#039;&#039; (algorithm graph) - это ориентированный ациклический мультиграф, вершины которого соответствуют операциям алгоритма, а дуги - передаче данных между ними. Вершины графа алгоритма могут соединяться несколькими дугами, в частности когда в качестве разных аргументов одной и той же операции используется одна и та же величина. Граф алгоритма почти всегда является параметризованным графом. В частности, его вид часто зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма используется как удобное представление алгоритма при исследовании его структуры, ресурса параллелизма, а также других свойств. Его можно рассматривать как параметризованную информационную историю. Он сохраняет её информативность, при этом обладая компактностью за счёт параметризации. Разработана методика построения графа алгоритма по исходному тексту программ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также: [https://ru.wikipedia.org/wiki/Граф_алгоритма Граф алгоритма]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&#039;&#039;&#039;Детерминированность&#039;&#039;&#039; (determinacy) алгоритма - постоянство структуры вычислительного процесса. Алгоритм выдаёт уникальный и предопределённый результат для заданных входных данных.&lt;br /&gt;
&lt;br /&gt;
=== Избыточные вычисления ===&lt;br /&gt;
&#039;&#039;&#039;Избыточные вычисления&#039;&#039;&#039; (redundant computation) - понятие, которое используют для обозначения разных явлений в параллельных вычислениях. &lt;br /&gt;
* В понимании графовой модели вычислений это такие операции, результаты которых нигде не будут использованы. Такие операции появляются в результате ошибок программирования и подлежат удалению из алгоритма. &lt;br /&gt;
* Распространено также понимание термина как вычисления, которые &#039;&#039;выполняются более одного раза&#039;&#039; или на более чем одном процессоре. Избыточные вычисления могут использоваться либо в многопроцессорных системах, чтобы минимизировать обмены, либо при недостаточном объеме памяти для хранения всех вычисленных значений. &lt;br /&gt;
* Кроме этого, избыточными вычислениями можно назвать те операции, которые появляются при замене последовательного алгоритма на специальный параллельный. У последнего алгоритма больше операций, но меньше длина критического пути графа, этим и обосновывается замена алгоритма. В таком случае реальное ускорение параллельного алгоритма следует считать не в сравнении с однопроцессорной реализацией его самого, а в сравнении с реализацией последовательного алгоритма. В нашей открытой энциклопедии свойств алгоритмов именно последнее толкование термина применяется в категории [[http://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D1%81_%D0%B8%D0%B7%D0%B1%D1%8B%D1%82%D0%BE%D1%87%D0%BD%D1%8B%D0%BC%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8 Алгоритмы с избыточными вычислениями]].&lt;br /&gt;
&lt;br /&gt;
=== Конечный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Конечный параллелизм&#039;&#039;&#039; (finite parallelism) - параллелизм, определяемый информационной независимостью некоторых фрагментов в тексте программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Координатный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Координатный параллелизм&#039;&#039;&#039; (coordinate parallelism) - частный случай [[#Скошенный паралеллизм|скошенного параллелизма]], определяемый циклами ParDO, при котором информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность (обращений в память) ===&lt;br /&gt;
&#039;&#039;&#039;Локальность (обращений в память)&#039;&#039;&#039; (locality) - общее предположение о свойстве работы программ с данными. Заключается в том, что при обращении к некоторым данным велика вероятность, что в скором времени произойдет повторное обращение к тем же или расположенным рядом данным. В частности, на основе данного предположения построена работа кэш-памяти. Различают [[#Локальность команд|локальность команд]] и [[#Локальность использования данных|локальность использования данных]], а также [[#Пространственная локальность|пространственную]] и [[#Временна́я локальность|временну́ю]] локальность.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность вычислений ===&lt;br /&gt;
&#039;&#039;&#039;Локальность вычислений&#039;&#039;&#039; (computation locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - команды, из которых состоят программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность использования данных ===&lt;br /&gt;
&#039;&#039;&#039;Локальность использования данных&#039;&#039;&#039; (data locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - все данные, с которыми оперируют программы во время выполнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Массовый параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Массовый параллелизм&#039;&#039;&#039; (mass parallelism) - параллелизм, определяемый информационной независимостью итераций циклов программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость&#039;&#039;&#039; (scalability) - способность системы увеличивать свою [[#Производительность|производительность]] при добавлении ресурсов (обычно аппаратных). Система называется масштабируемой, если она способна увеличивать производительность пропорционально дополнительным ресурсам. Масштабируемость можно оценить через отношение прироста производительности системы к приросту используемых ей ресурсов. Чем ближе это отношение к единице, тем масштабируемость лучше.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость параллельной программы ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость параллельной программы&#039;&#039;&#039; (scalability of parallel program) определяется относительно конкретного компьютера и показывает, как изменяются динамические характеристики данной программы в зависимости от её [[#Параметры запуска|параметров запуска]].&lt;br /&gt;
&lt;br /&gt;
Наиболее часто рассматриваемые разновидности масштабируемости параллельных программ: [[#Сильная масштабируемость|сильная масштабируемость]], [[#Масштабируемость вширь|масштабируемость вширь]], [[#Слабая масштабируемость|слабая масштабируемость]].&lt;br /&gt;
&lt;br /&gt;
Если при одновременном увеличении числа процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; и [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; [[#Эффективность распараллеливания|эффективность распараллеливания]] &amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; остаётся прежней, то данную программу на данном компьютере можно считать масштабируемой.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость вширь ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость вширь&#039;&#039;&#039; (wide scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; при фиксированном числе процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка daps ===&lt;br /&gt;
&#039;&#039;&#039;Оценка daps&#039;&#039;&#039; (daps estimation) - предлагаемая оценка производительности работы с памятью в программе, равна числу выполненных обращений в память в секунду. Построена по аналогии с распространенной оценкой производительности программ — flop/s (floating point operations per second), которая оценивает число операций с плавающей запятой в секунду. Оценка flop/s показывает производительность всей программы с точки зрения производимых вычислений; в то время как daps оценивает производительность программы с точки зрения работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Данная оценка является машинно-зависимой — она вычисляется на основе данных аппаратных датчиков. Служит для проверки точности результатов разрабатываемых нами машинно-независимых оценок локальности, таких как [[#Оценка cvg|cvg]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка cvg ===&lt;br /&gt;
&#039;&#039;&#039;Оценка cvg&#039;&#039;&#039; (cvg estimation) - предлагаемая машинно-независимая оценка локальности обращений в памяти в программе. Рассмотрим первые N обращений в потоке («окно»), и затем разобьем ось ординат (виртуальный адрес обращений) на отрезки длины K – [X .. X+K],  [X+K .. X+2K], …, [Y-K .. Y], где [X, Y] - диапазон выделенной под рассматриваемые массивы виртуальной памяти. Таким образом, область построения профиля делится на прямоугольники размером KxN. &lt;br /&gt;
&lt;br /&gt;
Физический смысл такого прямоугольника (при правильно подобранных значениях K и N) заключается в том, что любая последовательность точек, попавших в один прямоугольник, всегда обладает хорошей как пространственной, так и временно́й локальностью. Действительно, при достаточно малом значении K в прямоугольник попадает небольшой локальный фрагмент виртуальной памяти, а, значит, соседние обращения по памяти в любом случае будут расположены близко друг относительно друга. А временна́я локальность внутри прямоугольника не может быть больше N, поэтому при достаточно малом N можно обеспечить и хорошую временну́ю локальность. Однако не имеет смысла брать слишком малые значения для K и N, поскольку в этом случае теряется полезная информация о хорошей локальности не попавшего в прямоугольник фрагмента профиля.&lt;br /&gt;
&lt;br /&gt;
Выделим те прямоугольники, в которые попадает хотя бы одно обращение. Чем меньше таких прямоугольников – тем больше точек попало в одни и те же прямоугольники, тем в общем случае лучше локальность. Пример разбиения профиля на прямоугольники приведен на рис. 1. Здесь для иллюстрации выделено три «окна», в каждом по 6 точек. В первом «окне» всего 2 непустых прямоугольника и самая хорошая локальность их трех вариантов. Во втором «окне» задействованы все 4 прямоугольника, при этом в каждый попало лишь по 1-2 обращения. Третье «окно» включает 3 непустых прямоугольника, и в этом варианте локальность лучше, чем у второго «окна», но хуже, чем у первого.&lt;br /&gt;
&lt;br /&gt;
[[file:cvg.png|thumb|center|500px|Рисунок 1. Пример разбиения профиля на прямоугольники]]&lt;br /&gt;
&lt;br /&gt;
Теперь сдвинем «окно» на одно обращение вправо и снова определим непустые прямоугольники; и так далее для всего профиля обращений. В результате мы получим «покрытие» – последовательность непустых прямоугольников, в каждом из которых содержится хотя бы по одному обращению, т.е. по одной точке профиля.&lt;br /&gt;
&lt;br /&gt;
Далее для каждого «окна» посчитаем число таких непустых прямоугольников (обозначим это число как rects), в результате чего получим последовательность положительных натуральных чисел. Затем посчитаем среднее значение для данной последовательности. Полученное значение назовем оценкой локальности на основе метода покрытий и будем обозначать cvg.&lt;br /&gt;
&lt;br /&gt;
Значение K было решено выбрать равным 64 байт, поскольку это соответствует длине кэш-строки, а в пределах одной кэш-строки пространственная локальность заведомо достаточно хорошая. При этом если запрошено одно значение, то в кэш-память подтянется вся строка из 64 байт, то есть все данные, соответствующие определенному прямоугольнику.&lt;br /&gt;
&lt;br /&gt;
Оптимальное значение N для разных программ может существенно отличаться, но для выполнения корректного сравнения оценка было решено выбрать единственное значение N. Было проведено сравнение результатов для различных значений N, и в результате эмпирическим путем было получено, что наилучшие результаты достигаются при N=512.&lt;br /&gt;
&lt;br /&gt;
=== Параллельная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Параллельная сложность&#039;&#039;&#039; (parallel complexity) алгоритма - число шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых процессоров (функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической [[#Ярусно-параллельная форма графа алгоритма|ярусно-параллельной формы]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Параметры запуска ===&lt;br /&gt;
&#039;&#039;&#039;Параметры запуска&#039;&#039;&#039; (startup parameters) параллельной программы - параметры, оказывающие влияние на работу параллельной программы, но не влияющие на реализацию алгоритма работы программы (например: размер задачи, число процессов, размер блока, число процессов на узел и т.п.) &lt;br /&gt;
Параметры запуска по типу можно разделить на:&lt;br /&gt;
# Аппаратные - относящиеся к параметрам аппаратуры.&lt;br /&gt;
# Системные - относящиеся к операционной системе, используемым библиотекам и системным приложениям и их настройкам.&lt;br /&gt;
# Программные - влияющие на логику работы программы или вычислительную сложность задачи, различные параметры, предусмотренные разработчиком.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пиковая производительность ===&lt;br /&gt;
&#039;&#039;&#039;Пиковая производительность&#039;&#039;&#039; (peak performance) &amp;lt;math&amp;gt;R_{peak}&amp;lt;/math&amp;gt; — теоретический предел [[#Производительность|производительности]] для данного компьютера. Пиковая производительность компьютера вычисляется как сумма пиковых производительностей всех входящих в него вычислительных устройств (процессоров, ускорителей и т.д.). Под пиковой производительностью каждого из вычислительных устройств понимают количество операций в секунду, которые он смог бы теоретически выполнять при полной загрузке всех своих компонент. Надо понимать, что пиковая производительность не только суперкомпьютера, но и, например, любого отдельно взятого процессора является величиной сугубо теоретической, недостижимой на практике.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Последовательная сложность&#039;&#039;&#039; (serial complexity) алгоритма - число операций, которые нужно выполнить при его последовательном исполнении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пространственная локальность ===&lt;br /&gt;
&#039;&#039;&#039;Пространственная локальность&#039;&#039;&#039; (spatial locality) отражает среднее расстояние между несколькими последовательными обращениями в память.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Производительность ===&lt;br /&gt;
&#039;&#039;&#039;Производительность&#039;&#039;&#039; (performance) &amp;lt;math&amp;gt;R=Op/t&amp;lt;/math&amp;gt; определяется количеством операций &amp;lt;math&amp;gt;Op&amp;lt;/math&amp;gt;, производимых данным компьютером в единицу времени. Для высокопроизводительных вычислений в расчёт обычно берут количество арифметических операций в секунду над вещественными данными, представленными в форме с плавающей точкой. Эта величина называется Flop/s (от английского Floating point operations per second).&lt;br /&gt;
&lt;br /&gt;
Поскольку современные суперкомпьютеры производят очень много таких операций в секунду, их производительность измеряется кратными величинами, такими как GFlop/s (&amp;lt;math&amp;gt;10^9&amp;lt;/math&amp;gt; операций в секунду), TFlop/s (&amp;lt;math&amp;gt;10^{12}&amp;lt;/math&amp;gt;), PFlop/s (&amp;lt;math&amp;gt;10^{15}&amp;lt;/math&amp;gt;), EFlop/s (&amp;lt;math&amp;gt;10^{18}&amp;lt;/math&amp;gt;). Производительность мощнейших современных суперкомпьютеров уже измеряется в EFlop/s, идёт обсуждение построения систем зеттафлопсного (порядка &amp;lt;math&amp;gt;10^{21}&amp;lt;/math&amp;gt; операций в секунду) уровня производительности.&lt;br /&gt;
&lt;br /&gt;
=== Профиль обращений в память ===&lt;br /&gt;
&#039;&#039;&#039;Профиль обращений в память&#039;&#039;&#039; (memory access profile) - последовательность выполняемых в программе обращений к данным в памяти, расположенных в том порядке, в котором обращения происходят в программе.&lt;br /&gt;
&lt;br /&gt;
Обозначим профиль обращений A = {A&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,A&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,…,A&amp;lt;sub&amp;gt;N&amp;lt;/sub&amp;gt;}, где N – общее число всех обращений при выполнении программы. Номер i элемента A&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; в профиле указывает, каким по счету является данное обращение от начала выполнения программы. Любой элемент А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; будем называть элементом профиля. Запись А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; означает, что данный элемент имеет i-й порядковый номер; данная запись не содержит никакой информации о том, к какой переменной в программе происходит данное обращение.&lt;br /&gt;
&lt;br /&gt;
На данный момент рассматриваются в основном обращения к массивам, поскольку они являются самыми распространенными структурами данных. Каждое обращение представлено в профиле некоторым числом. Таким образом, профиль обращений представляет собой последовательность чисел, которыми могут являться: 1) индексы элементов массива (если профиль строится только для одного массива); 2) виртуальные адреса, к которым происходят обращения; 3) физические адреса. Естественно, в рамках одного профиля используются числа только одного типа.&lt;br /&gt;
&lt;br /&gt;
Подобные профили обращений содержат огромное количество полезной информации о работе программы с памятью. Интересным средством анализа профилей является изучение их визуального представления. Пример визуализации профиля приведен на рис. 2. Ось абсцисс — порядковый номер обращения в память, т. е. чем больше номер, тем позже произошло данное обращение. По оси ординат отложен виртуальный адрес памяти, к которому произошло обращение. Каждая точка — это отдельное обращение в память. &lt;br /&gt;
&lt;br /&gt;
[[file:locality_profile.png|thumb|center|500px|Рисунок 2. Визуализация профиля обращений в память]]&lt;br /&gt;
&lt;br /&gt;
Подобные графики сами по себе могут предоставить интересную информацию о поведении программы. Выделенная на рисунке область 1 (и остальные, аналогичные ей области), скорее всего, обладает хорошей пространственной и временно́й локальностью. Хорошей пространственной — потому что используются только соседние по памяти данные; хорошей временно́й — поскольку повторные обращения к этим данным происходят часто. Область 2 также обладает хорошей пространственной локальностью, поскольку соседние обращения происходят к соседним элементам, однако плохой временно́й локальностью, поскольку повторных обращений к данным просто нет.&lt;br /&gt;
&lt;br /&gt;
Помимо получения данных о локальности, исследование визуализации профилей обращений в память является хорошим средством для понимания и определения шаблонов обращений.&lt;br /&gt;
&lt;br /&gt;
Подобный анализ на основе визуализации профиля обращений помогает понять общее поведение программы, однако он не может дать точной количественной информации о взаимодействии программ с памятью. Для этих целей разрабатываются оценки локальности, такие как [[#Оценка daps|daps]] и [[#Оценка cvg|cvg]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Реальная производительность ===&lt;br /&gt;
&#039;&#039;&#039;Реальная производительность&#039;&#039;&#039; (real performance) &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; — [[#Производительность|производительность]] данного компьютера на конкретном приложении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Сильная масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Сильная масштабируемость&#039;&#039;&#039; (strong scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи (&amp;lt;math&amp;gt;W=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скошенный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Скошенный параллелизм&#039;&#039;&#039; (skewed parallelism) - параллелизм в пространстве итераций, определяемый поверхностями уровней разверток. Ряд исследователей этим термином пользуется только для случая, когда параллелизм не является [[#Координатный паралеллизм|координатным]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Слабая масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Слабая масштабируемость&#039;&#039;&#039; (weak scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи в пересчёте на один процессор (&amp;lt;math&amp;gt;W/p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Степень исхода ===&lt;br /&gt;
&#039;&#039;&#039;Степень исхода&#039;&#039;&#039; (degree of a vertex) вершины информационного графа - количество исходящих из данной вершины информационных дуг.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Суперлинейное ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Суперлинейное ускорение&#039;&#039;&#039; (super linear speedup) или &#039;&#039;&#039;сверхлинейное ускорение&#039;&#039;&#039; программы - это [[#Ускорение|ускорение]], превосходящие число используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Чаще всего объясняется эффектом от использования кэш-памяти.&lt;br /&gt;
&lt;br /&gt;
=== Суперскалярность ===&lt;br /&gt;
&#039;&#039;&#039;Суперскалярность&#039;&#039;&#039; — архитектура вычислительного ядра, позволяющая загружать работой множество исполнительных блоков. Планирование исполнения команд является динамическим и осуществляется самим ядром. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Суперскалярность Суперскалярность]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Ускорение&#039;&#039;&#039; (speedup) работы программы &amp;lt;math&amp;gt;S = T_1/T_p&amp;lt;/math&amp;gt; - отношение времени работы некоторой программы на одном процессоре &amp;lt;math&amp;gt;T_1&amp;lt;/math&amp;gt; ко времени работы распараллеленной программы при использовании &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; процессоров &amp;lt;math&amp;gt;T_p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&#039;&#039;&#039;Устойчивость&#039;&#039;&#039; (stability) алгоритма - свойство алгоритма не увеличивать или увеличивать в незначительной степени погрешности, допущенной в начальных данных или допускаемой при вычислениях.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное возмущение ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное возмущение&#039;&#039;&#039; (equivalent perturbation) алгоритма - одна из характеристик влияния ошибок округления промежуточных операций на отклонение решения, получаемого алгоритмом, от настоящего решения задачи. Выражается косвенно: влияние ошибок на ответ считается таким же, как если бы данные были заданы с ошибкой, выражаемой эквивалентным возмущением, но задача с такими данными была бы решена точно.&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное преобразование ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное преобразование&#039;&#039;&#039; (equivalent transformaion) программы - такое преобразование, при котором в точности сохраняется результат выполнения программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность распараллеливания ===&lt;br /&gt;
&#039;&#039;&#039;Эффективность распараллеливания&#039;&#039;&#039; (parallel efficiency) &amp;lt;math&amp;gt;E = S/p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; - полученное [[#Ускорение|ускорение]] работы программы, а &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число используемых процессоров) определяет среднюю долю времени выполнения параллельного алгоритма, в течение которого процессоры реально используются для решения задачи. Получение большого ускорения за счёт использования большого числа процессоров зачастую приводит к снижению эффективности.&lt;br /&gt;
&lt;br /&gt;
Если не брать в расчёт эффект [[#Суперлинейное ускорение|суперлинейного ускорения]], то ускорение выполнения программы не превосходит числа используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;, а значит, эффективность распараллеливания не превосходит единицы. Чем ближе этот показатель к единице, тем лучше для пользователя, поскольку говорит о меньшем количестве накладных расходов, а значит, о лучшем качестве распараллеливания программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность реализации ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эффективность реализации&#039;&#039;&#039; (implementation efficiency) программы &amp;lt;math&amp;gt;R_{max}/R_{peak}&amp;lt;/math&amp;gt; определяется как отношение [[#Реальная производительность|реальной производительности]] &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; к [[#Пиковая производительность|пиковой производительности]] &amp;lt;math&amp;gt;R_{peak}&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;
&#039;&#039;&#039;Ярусно-параллельная форма (ЯПФ)&#039;&#039;&#039; (parallel form) - это представление графа алгоритма, в котором:&lt;br /&gt;
* все вершины разбиты на перенумерованные подмножества ярусов;&lt;br /&gt;
* начальная вершина каждой дуги расположена на ярусе с номером меньшим, чем номер яруса конечной вершины;&lt;br /&gt;
* между вершинами, расположенными на одном ярусе, не может быть дуг.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Высота&#039;&#039; ЯПФ - это число ярусов.&lt;br /&gt;
Ширина яруса - число вершин, расположенных на ярусе.&lt;br /&gt;
&#039;&#039;Ширина&#039;&#039; ЯПФ - это максимальная ширина ярусов в ЯПФ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Канонической ярусно-параллельной формой&#039;&#039;&#039; называется ЯПФ, высота которой на единицу больше длины критического пути, а все входные вершины расположены на первом ярусе. Для заданного графа его каноническая ЯПФ единственна. Высота канонической ЯПФ соответствует [[#Параллельная сложность|параллельной сложности]] алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Ярусно-параллельная_форма_графа Ярусно-параллельная форма графа]&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Критический_путь_графа Критический путь графа]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[En:Glossary]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Algowiki:Справка]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=29728</id>
		<title>Глоссарий</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=29728"/>
		<updated>2025-03-14T10:05:40Z</updated>

		<summary type="html">&lt;p&gt;ASA: /* Производительность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Временна́я локальность ===&lt;br /&gt;
&#039;&#039;&#039;Временная локальность&#039;&#039;&#039; (temporal locality) показывает среднее число обращений по одному адресу в память за время исполнения всей программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная мощность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная мощность&#039;&#039;&#039; (computational power) алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная сложность&#039;&#039;&#039; (computational complexity) задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; - количество основных вычислительных шагов лучшего последовательного алгоритма, необходимых для решения задачи на одном процессоре. Вычислительная сложность обычно является некоторой функцией от размера входных данных программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительное ядро&#039;&#039;&#039; (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Граф алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Граф алгоритма&#039;&#039;&#039; (algorithm graph) - это ориентированный ациклический мультиграф, вершины которого соответствуют операциям алгоритма, а дуги - передаче данных между ними. Вершины графа алгоритма могут соединяться несколькими дугами, в частности когда в качестве разных аргументов одной и той же операции используется одна и та же величина. Граф алгоритма почти всегда является параметризованным графом. В частности, его вид часто зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма используется как удобное представление алгоритма при исследовании его структуры, ресурса параллелизма, а также других свойств. Его можно рассматривать как параметризованную информационную историю. Он сохраняет её информативность, при этом обладая компактностью за счёт параметризации. Разработана методика построения графа алгоритма по исходному тексту программ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также: [https://ru.wikipedia.org/wiki/Граф_алгоритма Граф алгоритма]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&#039;&#039;&#039;Детерминированность&#039;&#039;&#039; (determinacy) алгоритма - постоянство структуры вычислительного процесса. Алгоритм выдаёт уникальный и предопределённый результат для заданных входных данных.&lt;br /&gt;
&lt;br /&gt;
=== Избыточные вычисления ===&lt;br /&gt;
&#039;&#039;&#039;Избыточные вычисления&#039;&#039;&#039; (redundant computation) - понятие, которое используют для обозначения разных явлений в параллельных вычислениях. &lt;br /&gt;
* В понимании графовой модели вычислений это такие операции, результаты которых нигде не будут использованы. Такие операции появляются в результате ошибок программирования и подлежат удалению из алгоритма. &lt;br /&gt;
* Распространено также понимание термина как вычисления, которые &#039;&#039;выполняются более одного раза&#039;&#039; или на более чем одном процессоре. Избыточные вычисления могут использоваться либо в многопроцессорных системах, чтобы минимизировать обмены, либо при недостаточном объеме памяти для хранения всех вычисленных значений. &lt;br /&gt;
* Кроме этого, избыточными вычислениями можно назвать те операции, которые появляются при замене последовательного алгоритма на специальный параллельный. У последнего алгоритма больше операций, но меньше длина критического пути графа, этим и обосновывается замена алгоритма. В таком случае реальное ускорение параллельного алгоритма следует считать не в сравнении с однопроцессорной реализацией его самого, а в сравнении с реализацией последовательного алгоритма. В нашей открытой энциклопедии свойств алгоритмов именно последнее толкование термина применяется в категории [[http://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D1%81_%D0%B8%D0%B7%D0%B1%D1%8B%D1%82%D0%BE%D1%87%D0%BD%D1%8B%D0%BC%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8 Алгоритмы с избыточными вычислениями]].&lt;br /&gt;
&lt;br /&gt;
=== Конечный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Конечный параллелизм&#039;&#039;&#039; (finite parallelism) - параллелизм, определяемый информационной независимостью некоторых фрагментов в тексте программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Координатный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Координатный параллелизм&#039;&#039;&#039; (coordinate parallelism) - частный случай [[#Скошенный паралеллизм|скошенного параллелизма]], определяемый циклами ParDO, при котором информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность (обращений в память) ===&lt;br /&gt;
&#039;&#039;&#039;Локальность (обращений в память)&#039;&#039;&#039; (locality) - общее предположение о свойстве работы программ с данными. Заключается в том, что при обращении к некоторым данным велика вероятность, что в скором времени произойдет повторное обращение к тем же или расположенным рядом данным. В частности, на основе данного предположения построена работа кэш-памяти. Различают [[#Локальность команд|локальность команд]] и [[#Локальность использования данных|локальность использования данных]], а также [[#Пространственная локальность|пространственную]] и [[#Временна́я локальность|временну́ю]] локальность.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность вычислений ===&lt;br /&gt;
&#039;&#039;&#039;Локальность вычислений&#039;&#039;&#039; (computation locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - команды, из которых состоят программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность использования данных ===&lt;br /&gt;
&#039;&#039;&#039;Локальность использования данных&#039;&#039;&#039; (data locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - все данные, с которыми оперируют программы во время выполнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Массовый параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Массовый параллелизм&#039;&#039;&#039; (mass parallelism) - параллелизм, определяемый информационной независимостью итераций циклов программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость&#039;&#039;&#039; (scalability) - способность системы увеличивать свою [[#Производительность|производительность]] при добавлении ресурсов (обычно аппаратных). Система называется масштабируемой, если она способна увеличивать производительность пропорционально дополнительным ресурсам. Масштабируемость можно оценить через отношение прироста производительности системы к приросту используемых ей ресурсов. Чем ближе это отношение к единице, тем масштабируемость лучше.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость параллельной программы ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость параллельной программы&#039;&#039;&#039; (scalability of parallel program) определяется относительно конкретного компьютера и показывает, как изменяются динамические характеристики данной программы в зависимости от её [[#Параметры запуска|параметров запуска]].&lt;br /&gt;
&lt;br /&gt;
Наиболее часто рассматриваемые разновидности масштабируемости параллельных программ: [[#Сильная масштабируемость|сильная масштабируемость]], [[#Масштабируемость вширь|масштабируемость вширь]], [[#Слабая масштабируемость|слабая масштабируемость]].&lt;br /&gt;
&lt;br /&gt;
Если при одновременном увеличении числа процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; и [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; [[#Эффективность распараллеливания|эффективность распараллеливания]] &amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; остаётся прежней, то данную программу на данном компьютере можно считать масштабируемой.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость вширь ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость вширь&#039;&#039;&#039; (wide scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; при фиксированном числе процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка daps ===&lt;br /&gt;
&#039;&#039;&#039;Оценка daps&#039;&#039;&#039; (daps estimation) - предлагаемая оценка производительности работы с памятью в программе, равна числу выполненных обращений в память в секунду. Построена по аналогии с распространенной оценкой производительности программ — flop/s (floating point operations per second), которая оценивает число операций с плавающей запятой в секунду. Оценка flop/s показывает производительность всей программы с точки зрения производимых вычислений; в то время как daps оценивает производительность программы с точки зрения работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Данная оценка является машинно-зависимой — она вычисляется на основе данных аппаратных датчиков. Служит для проверки точности результатов разрабатываемых нами машинно-независимых оценок локальности, таких как [[#Оценка cvg|cvg]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка cvg ===&lt;br /&gt;
&#039;&#039;&#039;Оценка cvg&#039;&#039;&#039; (cvg estimation) - предлагаемая машинно-независимая оценка локальности обращений в памяти в программе. Рассмотрим первые N обращений в потоке («окно»), и затем разобьем ось ординат (виртуальный адрес обращений) на отрезки длины K – [X .. X+K],  [X+K .. X+2K], …, [Y-K .. Y], где [X, Y] - диапазон выделенной под рассматриваемые массивы виртуальной памяти. Таким образом, область построения профиля делится на прямоугольники размером KxN. &lt;br /&gt;
&lt;br /&gt;
Физический смысл такого прямоугольника (при правильно подобранных значениях K и N) заключается в том, что любая последовательность точек, попавших в один прямоугольник, всегда обладает хорошей как пространственной, так и временно́й локальностью. Действительно, при достаточно малом значении K в прямоугольник попадает небольшой локальный фрагмент виртуальной памяти, а, значит, соседние обращения по памяти в любом случае будут расположены близко друг относительно друга. А временна́я локальность внутри прямоугольника не может быть больше N, поэтому при достаточно малом N можно обеспечить и хорошую временну́ю локальность. Однако не имеет смысла брать слишком малые значения для K и N, поскольку в этом случае теряется полезная информация о хорошей локальности не попавшего в прямоугольник фрагмента профиля.&lt;br /&gt;
&lt;br /&gt;
Выделим те прямоугольники, в которые попадает хотя бы одно обращение. Чем меньше таких прямоугольников – тем больше точек попало в одни и те же прямоугольники, тем в общем случае лучше локальность. Пример разбиения профиля на прямоугольники приведен на рис. 1. Здесь для иллюстрации выделено три «окна», в каждом по 6 точек. В первом «окне» всего 2 непустых прямоугольника и самая хорошая локальность их трех вариантов. Во втором «окне» задействованы все 4 прямоугольника, при этом в каждый попало лишь по 1-2 обращения. Третье «окно» включает 3 непустых прямоугольника, и в этом варианте локальность лучше, чем у второго «окна», но хуже, чем у первого.&lt;br /&gt;
&lt;br /&gt;
[[file:cvg.png|thumb|center|500px|Рисунок 1. Пример разбиения профиля на прямоугольники]]&lt;br /&gt;
&lt;br /&gt;
Теперь сдвинем «окно» на одно обращение вправо и снова определим непустые прямоугольники; и так далее для всего профиля обращений. В результате мы получим «покрытие» – последовательность непустых прямоугольников, в каждом из которых содержится хотя бы по одному обращению, т.е. по одной точке профиля.&lt;br /&gt;
&lt;br /&gt;
Далее для каждого «окна» посчитаем число таких непустых прямоугольников (обозначим это число как rects), в результате чего получим последовательность положительных натуральных чисел. Затем посчитаем среднее значение для данной последовательности. Полученное значение назовем оценкой локальности на основе метода покрытий и будем обозначать cvg.&lt;br /&gt;
&lt;br /&gt;
Значение K было решено выбрать равным 64 байт, поскольку это соответствует длине кэш-строки, а в пределах одной кэш-строки пространственная локальность заведомо достаточно хорошая. При этом если запрошено одно значение, то в кэш-память подтянется вся строка из 64 байт, то есть все данные, соответствующие определенному прямоугольнику.&lt;br /&gt;
&lt;br /&gt;
Оптимальное значение N для разных программ может существенно отличаться, но для выполнения корректного сравнения оценка было решено выбрать единственное значение N. Было проведено сравнение результатов для различных значений N, и в результате эмпирическим путем было получено, что наилучшие результаты достигаются при N=512.&lt;br /&gt;
&lt;br /&gt;
=== Параллельная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Параллельная сложность&#039;&#039;&#039; (parallel complexity) алгоритма - число шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых процессоров (функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической [[#Ярусно-параллельная форма графа алгоритма|ярусно-параллельной формы]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Параметры запуска ===&lt;br /&gt;
&#039;&#039;&#039;Параметры запуска&#039;&#039;&#039; (startup parameters) параллельной программы - параметры, оказывающие влияние на работу параллельной программы, но не влияющие на реализацию алгоритма работы программы (например: размер задачи, число процессов, размер блока, число процессов на узел и т.п.) &lt;br /&gt;
Параметры запуска по типу можно разделить на:&lt;br /&gt;
# Аппаратные - относящиеся к параметрам аппаратуры.&lt;br /&gt;
# Системные - относящиеся к операционной системе, используемым библиотекам и системным приложениям и их настройкам.&lt;br /&gt;
# Программные - влияющие на логику работы программы или вычислительную сложность задачи, различные параметры, предусмотренные разработчиком.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пиковая производительность ===&lt;br /&gt;
&#039;&#039;&#039;Пиковая производительность&#039;&#039;&#039; (peak performance) &amp;lt;math&amp;gt;R_{peak}&amp;lt;/math&amp;gt; — теоретический предел [[#Производительность|производительности]] для данного компьютера. Пиковая производительность компьютера вычисляется как сумма пиковых производительностей всех входящих в него вычислительных устройств (процессоров, ускорителей и т.д.). Под пиковой производительностью каждого из вычислительных устройств понимают количество операций в секунду, которые он смог бы теоретически выполнять при полной загрузке всех своих компонент. Надо понимать, что пиковая производительность не только суперкомпьютера, но и, например, любого отдельно взятого процессора является величиной сугубо теоретической, недостижимой на практике.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Последовательная сложность&#039;&#039;&#039; (serial complexity) алгоритма - число операций, которые нужно выполнить при его последовательном исполнении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пространственная локальность ===&lt;br /&gt;
&#039;&#039;&#039;Пространственная локальность&#039;&#039;&#039; (spatial locality) отражает среднее расстояние между несколькими последовательными обращениями в память.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Производительность ===&lt;br /&gt;
&#039;&#039;&#039;Производительность&#039;&#039;&#039; (performance) &amp;lt;math&amp;gt;R=Op/t&amp;lt;/math&amp;gt; определяется количеством операций &amp;lt;math&amp;gt;Op&amp;lt;/math&amp;gt;, производимых данным компьютером в единицу времени. Для высокопроизводительных вычислений в расчёт обычно берут количество арифметических операций в секунду над вещественными данными, представленными в форме с плавающей точкой. Эта величина называется Flop/s (от английского Floating point operations per second).&lt;br /&gt;
&lt;br /&gt;
Поскольку современные суперкомпьютеры производят очень много таких операций в секунду, их производительность измеряется кратными величинами, такими как GFlop/s (&amp;lt;math&amp;gt;10^9&amp;lt;/math&amp;gt; операций в секунду), TFlop/s (&amp;lt;math&amp;gt;10^{12}&amp;lt;/math&amp;gt;), PFlop/s (&amp;lt;math&amp;gt;10^{15}&amp;lt;/math&amp;gt;), EFlop/s (&amp;lt;math&amp;gt;10^{18}&amp;lt;/math&amp;gt;). Производительность мощнейших современных суперкомпьютеров уже измеряется в EFlop/s, идёт обсуждение построения систем зеттафлопсного (порядка &amp;lt;math&amp;gt;10^{21}&amp;lt;/math&amp;gt; операций в секунду) уровня производительности.&lt;br /&gt;
&lt;br /&gt;
=== Профиль обращений в память ===&lt;br /&gt;
&#039;&#039;&#039;Профиль обращений в память&#039;&#039;&#039; (memory access profile) - последовательность выполняемых в программе обращений к данным в памяти, расположенных в том порядке, в котором обращения происходят в программе.&lt;br /&gt;
&lt;br /&gt;
Обозначим профиль обращений A = {A&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,A&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,…,A&amp;lt;sub&amp;gt;N&amp;lt;/sub&amp;gt;}, где N – общее число всех обращений при выполнении программы. Номер i элемента A&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; в профиле указывает, каким по счету является данное обращение от начала выполнения программы. Любой элемент А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; будем называть элементом профиля. Запись А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; означает, что данный элемент имеет i-й порядковый номер; данная запись не содержит никакой информации о том, к какой переменной в программе происходит данное обращение.&lt;br /&gt;
&lt;br /&gt;
На данный момент рассматриваются в основном обращения к массивам, поскольку они являются самыми распространенными структурами данных. Каждое обращение представлено в профиле некоторым числом. Таким образом, профиль обращений представляет собой последовательность чисел, которыми могут являться: 1) индексы элементов массива (если профиль строится только для одного массива); 2) виртуальные адреса, к которым происходят обращения; 3) физические адреса. Естественно, в рамках одного профиля используются числа только одного типа.&lt;br /&gt;
&lt;br /&gt;
Подобные профили обращений содержат огромное количество полезной информации о работе программы с памятью. Интересным средством анализа профилей является изучение их визуального представления. Пример визуализации профиля приведен на рис. 2. Ось абсцисс — порядковый номер обращения в память, т. е. чем больше номер, тем позже произошло данное обращение. По оси ординат отложен виртуальный адрес памяти, к которому произошло обращение. Каждая точка — это отдельное обращение в память. &lt;br /&gt;
&lt;br /&gt;
[[file:locality_profile.png|thumb|center|500px|Рисунок 2. Визуализация профиля обращений в память]]&lt;br /&gt;
&lt;br /&gt;
Подобные графики сами по себе могут предоставить интересную информацию о поведении программы. Выделенная на рисунке область 1 (и остальные, аналогичные ей области), скорее всего, обладает хорошей пространственной и временно́й локальностью. Хорошей пространственной — потому что используются только соседние по памяти данные; хорошей временно́й — поскольку повторные обращения к этим данным происходят часто. Область 2 также обладает хорошей пространственной локальностью, поскольку соседние обращения происходят к соседним элементам, однако плохой временно́й локальностью, поскольку повторных обращений к данным просто нет.&lt;br /&gt;
&lt;br /&gt;
Помимо получения данных о локальности, исследование визуализации профилей обращений в память является хорошим средством для понимания и определения шаблонов обращений.&lt;br /&gt;
&lt;br /&gt;
Подобный анализ на основе визуализации профиля обращений помогает понять общее поведение программы, однако он не может дать точной количественной информации о взаимодействии программ с памятью. Для этих целей разрабатываются оценки локальности, такие как [[#Оценка daps|daps]] и [[#Оценка cvg|cvg]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Реальная производительность ===&lt;br /&gt;
&#039;&#039;&#039;Реальная производительность&#039;&#039;&#039; (real performance) &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; — [[#Производительность|производительность]] данного компьютера на конкретном приложении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Сильная масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Сильная масштабируемость&#039;&#039;&#039; (strong scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи (&amp;lt;math&amp;gt;W=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скошенный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Скошенный параллелизм&#039;&#039;&#039; (skewed parallelism) - параллелизм в пространстве итераций, определяемый поверхностями уровней разверток. Ряд исследователей этим термином пользуется только для случая, когда параллелизм не является [[#Координатный паралеллизм|координатным]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Слабая масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Слабая масштабируемость&#039;&#039;&#039; (weak scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи в пересчёте на один процессор (&amp;lt;math&amp;gt;W/p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Степень исхода ===&lt;br /&gt;
&#039;&#039;&#039;Степень исхода&#039;&#039;&#039; (degree of a vertex) вершины информационного графа - количество исходящих из данной вершины информационных дуг.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Суперлинейное ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Суперлинейное ускорение&#039;&#039;&#039; (super linear speedup) или &#039;&#039;&#039;сверхлинейное ускорение&#039;&#039;&#039; программы - это [[#Ускорение|ускорение]], превосходящие число используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Чаще всего объясняется эффектом от использования кэш-памяти.&lt;br /&gt;
&lt;br /&gt;
=== Суперскалярность ===&lt;br /&gt;
&#039;&#039;&#039;Суперскалярность&#039;&#039;&#039; — архитектура вычислительного ядра, позволяющая загружать работой множество исполнительных блоков. Планирование исполнения команд является динамическим и осуществляется самим ядром. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Суперскалярность Суперскалярность]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Ускорение&#039;&#039;&#039; (speedup) работы программы &amp;lt;math&amp;gt;S = T_1/T_p&amp;lt;/math&amp;gt; - отношение времени работы некоторой программы на одном процессоре &amp;lt;math&amp;gt;T_1&amp;lt;/math&amp;gt; ко времени работы распараллеленной программы при использовании &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; процессоров &amp;lt;math&amp;gt;T_p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&#039;&#039;&#039;Устойчивость&#039;&#039;&#039; (stability) алгоритма - свойство алгоритма не увеличивать или увеличивать в незначительной степени погрешности, допущенной в начальных данных или допускаемой при вычислениях.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное возмущение ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное возмущение&#039;&#039;&#039; (equivalent perturbation) алгоритма - одна из характеристик влияния ошибок округления промежуточных операций на отклонение решения, получаемого алгоритмом, от настоящего решения задачи. Выражается косвенно: влияние ошибок на ответ считается таким же, как если бы данные были заданы с ошибкой, выражаемым эквивалентным возмущением, но задача с такими данными была бы решена точно.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное преобразование ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное преобразование&#039;&#039;&#039; (equivalent transformaion) программы - такое преобразование, при котором в точности сохраняется результат выполнения программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность распараллеливания ===&lt;br /&gt;
&#039;&#039;&#039;Эффективность распараллеливания&#039;&#039;&#039; (parallel efficiency) &amp;lt;math&amp;gt;E = S/p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; - полученное [[#Ускорение|ускорение]] работы программы, а &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число используемых процессоров) определяет среднюю долю времени выполнения параллельного алгоритма, в течение которого процессоры реально используются для решения задачи. Получение большого ускорения за счёт использования большого числа процессоров зачастую приводит к снижению эффективности.&lt;br /&gt;
&lt;br /&gt;
Если не брать в расчёт эффект [[#Суперлинейное ускорение|суперлинейного ускорения]], то ускорение выполнения программы не превосходит числа используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;, а значит, эффективность распараллеливания не превосходит единицы. Чем ближе этот показатель к единице, тем лучше для пользователя, поскольку говорит о меньшем количестве накладных расходов, а значит, о лучшем качестве распараллеливания программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность реализации ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эффективность реализации&#039;&#039;&#039; (implementation efficiency) программы &amp;lt;math&amp;gt;R_{max}/R_{peak}&amp;lt;/math&amp;gt; определяется как отношение [[#Реальная производительность|реальной производительности]] &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; к [[#Пиковая производительность|пиковой производительности]] &amp;lt;math&amp;gt;R_{peak}&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;
&#039;&#039;&#039;Ярусно-параллельная форма (ЯПФ)&#039;&#039;&#039; (parallel form) - это представление графа алгоритма, в котором:&lt;br /&gt;
* все вершины разбиты на перенумерованные подмножества ярусов;&lt;br /&gt;
* начальная вершина каждой дуги расположена на ярусе с номером меньшим, чем номер яруса конечной вершины;&lt;br /&gt;
* между вершинами, расположенными на одном ярусе, не может быть дуг.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Высота&#039;&#039; ЯПФ - это число ярусов.&lt;br /&gt;
Ширина яруса - число вершин, расположенных на ярусе.&lt;br /&gt;
&#039;&#039;Ширина&#039;&#039; ЯПФ - это максимальная ширина ярусов в ЯПФ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Канонической ярусно-параллельной формой&#039;&#039;&#039; называется ЯПФ, высота которой на единицу больше длины критического пути, а все входные вершины расположены на первом ярусе. Для заданного графа его каноническая ЯПФ единственна. Высота канонической ЯПФ соответствует [[#Параллельная сложность|параллельной сложности]] алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Ярусно-параллельная_форма_графа Ярусно-параллельная форма графа]&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Критический_путь_графа Критический путь графа]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[En:Glossary]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Algowiki:Справка]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=29727</id>
		<title>Глоссарий</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9&amp;diff=29727"/>
		<updated>2025-03-14T10:04:54Z</updated>

		<summary type="html">&lt;p&gt;ASA: /* Производительность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Временна́я локальность ===&lt;br /&gt;
&#039;&#039;&#039;Временная локальность&#039;&#039;&#039; (temporal locality) показывает среднее число обращений по одному адресу в память за время исполнения всей программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная мощность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная мощность&#039;&#039;&#039; (computational power) алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительная сложность&#039;&#039;&#039; (computational complexity) задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; - количество основных вычислительных шагов лучшего последовательного алгоритма, необходимых для решения задачи на одном процессоре. Вычислительная сложность обычно является некоторой функцией от размера входных данных программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро ===&lt;br /&gt;
&#039;&#039;&#039;Вычислительное ядро&#039;&#039;&#039; (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Граф алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Граф алгоритма&#039;&#039;&#039; (algorithm graph) - это ориентированный ациклический мультиграф, вершины которого соответствуют операциям алгоритма, а дуги - передаче данных между ними. Вершины графа алгоритма могут соединяться несколькими дугами, в частности когда в качестве разных аргументов одной и той же операции используется одна и та же величина. Граф алгоритма почти всегда является параметризованным графом. В частности, его вид часто зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма используется как удобное представление алгоритма при исследовании его структуры, ресурса параллелизма, а также других свойств. Его можно рассматривать как параметризованную информационную историю. Он сохраняет её информативность, при этом обладая компактностью за счёт параметризации. Разработана методика построения графа алгоритма по исходному тексту программ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также: [https://ru.wikipedia.org/wiki/Граф_алгоритма Граф алгоритма]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&#039;&#039;&#039;Детерминированность&#039;&#039;&#039; (determinacy) алгоритма - постоянство структуры вычислительного процесса. Алгоритм выдаёт уникальный и предопределённый результат для заданных входных данных.&lt;br /&gt;
&lt;br /&gt;
=== Избыточные вычисления ===&lt;br /&gt;
&#039;&#039;&#039;Избыточные вычисления&#039;&#039;&#039; (redundant computation) - понятие, которое используют для обозначения разных явлений в параллельных вычислениях. &lt;br /&gt;
* В понимании графовой модели вычислений это такие операции, результаты которых нигде не будут использованы. Такие операции появляются в результате ошибок программирования и подлежат удалению из алгоритма. &lt;br /&gt;
* Распространено также понимание термина как вычисления, которые &#039;&#039;выполняются более одного раза&#039;&#039; или на более чем одном процессоре. Избыточные вычисления могут использоваться либо в многопроцессорных системах, чтобы минимизировать обмены, либо при недостаточном объеме памяти для хранения всех вычисленных значений. &lt;br /&gt;
* Кроме этого, избыточными вычислениями можно назвать те операции, которые появляются при замене последовательного алгоритма на специальный параллельный. У последнего алгоритма больше операций, но меньше длина критического пути графа, этим и обосновывается замена алгоритма. В таком случае реальное ускорение параллельного алгоритма следует считать не в сравнении с однопроцессорной реализацией его самого, а в сравнении с реализацией последовательного алгоритма. В нашей открытой энциклопедии свойств алгоритмов именно последнее толкование термина применяется в категории [[http://algowiki-project.org/ru/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D1%81_%D0%B8%D0%B7%D0%B1%D1%8B%D1%82%D0%BE%D1%87%D0%BD%D1%8B%D0%BC%D0%B8_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8 Алгоритмы с избыточными вычислениями]].&lt;br /&gt;
&lt;br /&gt;
=== Конечный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Конечный параллелизм&#039;&#039;&#039; (finite parallelism) - параллелизм, определяемый информационной независимостью некоторых фрагментов в тексте программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Координатный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Координатный параллелизм&#039;&#039;&#039; (coordinate parallelism) - частный случай [[#Скошенный паралеллизм|скошенного параллелизма]], определяемый циклами ParDO, при котором информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность (обращений в память) ===&lt;br /&gt;
&#039;&#039;&#039;Локальность (обращений в память)&#039;&#039;&#039; (locality) - общее предположение о свойстве работы программ с данными. Заключается в том, что при обращении к некоторым данным велика вероятность, что в скором времени произойдет повторное обращение к тем же или расположенным рядом данным. В частности, на основе данного предположения построена работа кэш-памяти. Различают [[#Локальность команд|локальность команд]] и [[#Локальность использования данных|локальность использования данных]], а также [[#Пространственная локальность|пространственную]] и [[#Временна́я локальность|временну́ю]] локальность.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность вычислений ===&lt;br /&gt;
&#039;&#039;&#039;Локальность вычислений&#039;&#039;&#039; (computation locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - команды, из которых состоят программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Локальность использования данных ===&lt;br /&gt;
&#039;&#039;&#039;Локальность использования данных&#039;&#039;&#039; (data locality) - проекция идеи [[#Локальность (обращений в память)|локальности]] на конкретный класс данных в памяти - все данные, с которыми оперируют программы во время выполнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Массовый параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Массовый параллелизм&#039;&#039;&#039; (mass parallelism) - параллелизм, определяемый информационной независимостью итераций циклов программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость&#039;&#039;&#039; (scalability) - способность системы увеличивать свою [[#Производительность|производительность]] при добавлении ресурсов (обычно аппаратных). Система называется масштабируемой, если она способна увеличивать производительность пропорционально дополнительным ресурсам. Масштабируемость можно оценить через отношение прироста производительности системы к приросту используемых ей ресурсов. Чем ближе это отношение к единице, тем масштабируемость лучше.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость параллельной программы ===&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость параллельной программы&#039;&#039;&#039; (scalability of parallel program) определяется относительно конкретного компьютера и показывает, как изменяются динамические характеристики данной программы в зависимости от её [[#Параметры запуска|параметров запуска]].&lt;br /&gt;
&lt;br /&gt;
Наиболее часто рассматриваемые разновидности масштабируемости параллельных программ: [[#Сильная масштабируемость|сильная масштабируемость]], [[#Масштабируемость вширь|масштабируемость вширь]], [[#Слабая масштабируемость|слабая масштабируемость]].&lt;br /&gt;
&lt;br /&gt;
Если при одновременном увеличении числа процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; и [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; [[#Эффективность распараллеливания|эффективность распараллеливания]] &amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; остаётся прежней, то данную программу на данном компьютере можно считать масштабируемой.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость вширь ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Масштабируемость вширь&#039;&#039;&#039; (wide scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от [[#Вычислительная сложность|вычислительной сложности]] задачи &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; при фиксированном числе процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка daps ===&lt;br /&gt;
&#039;&#039;&#039;Оценка daps&#039;&#039;&#039; (daps estimation) - предлагаемая оценка производительности работы с памятью в программе, равна числу выполненных обращений в память в секунду. Построена по аналогии с распространенной оценкой производительности программ — flop/s (floating point operations per second), которая оценивает число операций с плавающей запятой в секунду. Оценка flop/s показывает производительность всей программы с точки зрения производимых вычислений; в то время как daps оценивает производительность программы с точки зрения работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Данная оценка является машинно-зависимой — она вычисляется на основе данных аппаратных датчиков. Служит для проверки точности результатов разрабатываемых нами машинно-независимых оценок локальности, таких как [[#Оценка cvg|cvg]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Оценка cvg ===&lt;br /&gt;
&#039;&#039;&#039;Оценка cvg&#039;&#039;&#039; (cvg estimation) - предлагаемая машинно-независимая оценка локальности обращений в памяти в программе. Рассмотрим первые N обращений в потоке («окно»), и затем разобьем ось ординат (виртуальный адрес обращений) на отрезки длины K – [X .. X+K],  [X+K .. X+2K], …, [Y-K .. Y], где [X, Y] - диапазон выделенной под рассматриваемые массивы виртуальной памяти. Таким образом, область построения профиля делится на прямоугольники размером KxN. &lt;br /&gt;
&lt;br /&gt;
Физический смысл такого прямоугольника (при правильно подобранных значениях K и N) заключается в том, что любая последовательность точек, попавших в один прямоугольник, всегда обладает хорошей как пространственной, так и временно́й локальностью. Действительно, при достаточно малом значении K в прямоугольник попадает небольшой локальный фрагмент виртуальной памяти, а, значит, соседние обращения по памяти в любом случае будут расположены близко друг относительно друга. А временна́я локальность внутри прямоугольника не может быть больше N, поэтому при достаточно малом N можно обеспечить и хорошую временну́ю локальность. Однако не имеет смысла брать слишком малые значения для K и N, поскольку в этом случае теряется полезная информация о хорошей локальности не попавшего в прямоугольник фрагмента профиля.&lt;br /&gt;
&lt;br /&gt;
Выделим те прямоугольники, в которые попадает хотя бы одно обращение. Чем меньше таких прямоугольников – тем больше точек попало в одни и те же прямоугольники, тем в общем случае лучше локальность. Пример разбиения профиля на прямоугольники приведен на рис. 1. Здесь для иллюстрации выделено три «окна», в каждом по 6 точек. В первом «окне» всего 2 непустых прямоугольника и самая хорошая локальность их трех вариантов. Во втором «окне» задействованы все 4 прямоугольника, при этом в каждый попало лишь по 1-2 обращения. Третье «окно» включает 3 непустых прямоугольника, и в этом варианте локальность лучше, чем у второго «окна», но хуже, чем у первого.&lt;br /&gt;
&lt;br /&gt;
[[file:cvg.png|thumb|center|500px|Рисунок 1. Пример разбиения профиля на прямоугольники]]&lt;br /&gt;
&lt;br /&gt;
Теперь сдвинем «окно» на одно обращение вправо и снова определим непустые прямоугольники; и так далее для всего профиля обращений. В результате мы получим «покрытие» – последовательность непустых прямоугольников, в каждом из которых содержится хотя бы по одному обращению, т.е. по одной точке профиля.&lt;br /&gt;
&lt;br /&gt;
Далее для каждого «окна» посчитаем число таких непустых прямоугольников (обозначим это число как rects), в результате чего получим последовательность положительных натуральных чисел. Затем посчитаем среднее значение для данной последовательности. Полученное значение назовем оценкой локальности на основе метода покрытий и будем обозначать cvg.&lt;br /&gt;
&lt;br /&gt;
Значение K было решено выбрать равным 64 байт, поскольку это соответствует длине кэш-строки, а в пределах одной кэш-строки пространственная локальность заведомо достаточно хорошая. При этом если запрошено одно значение, то в кэш-память подтянется вся строка из 64 байт, то есть все данные, соответствующие определенному прямоугольнику.&lt;br /&gt;
&lt;br /&gt;
Оптимальное значение N для разных программ может существенно отличаться, но для выполнения корректного сравнения оценка было решено выбрать единственное значение N. Было проведено сравнение результатов для различных значений N, и в результате эмпирическим путем было получено, что наилучшие результаты достигаются при N=512.&lt;br /&gt;
&lt;br /&gt;
=== Параллельная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Параллельная сложность&#039;&#039;&#039; (parallel complexity) алгоритма - число шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых процессоров (функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической [[#Ярусно-параллельная форма графа алгоритма|ярусно-параллельной формы]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Параметры запуска ===&lt;br /&gt;
&#039;&#039;&#039;Параметры запуска&#039;&#039;&#039; (startup parameters) параллельной программы - параметры, оказывающие влияние на работу параллельной программы, но не влияющие на реализацию алгоритма работы программы (например: размер задачи, число процессов, размер блока, число процессов на узел и т.п.) &lt;br /&gt;
Параметры запуска по типу можно разделить на:&lt;br /&gt;
# Аппаратные - относящиеся к параметрам аппаратуры.&lt;br /&gt;
# Системные - относящиеся к операционной системе, используемым библиотекам и системным приложениям и их настройкам.&lt;br /&gt;
# Программные - влияющие на логику работы программы или вычислительную сложность задачи, различные параметры, предусмотренные разработчиком.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пиковая производительность ===&lt;br /&gt;
&#039;&#039;&#039;Пиковая производительность&#039;&#039;&#039; (peak performance) &amp;lt;math&amp;gt;R_{peak}&amp;lt;/math&amp;gt; — теоретический предел [[#Производительность|производительности]] для данного компьютера. Пиковая производительность компьютера вычисляется как сумма пиковых производительностей всех входящих в него вычислительных устройств (процессоров, ускорителей и т.д.). Под пиковой производительностью каждого из вычислительных устройств понимают количество операций в секунду, которые он смог бы теоретически выполнять при полной загрузке всех своих компонент. Надо понимать, что пиковая производительность не только суперкомпьютера, но и, например, любого отдельно взятого процессора является величиной сугубо теоретической, недостижимой на практике.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность ===&lt;br /&gt;
&#039;&#039;&#039;Последовательная сложность&#039;&#039;&#039; (serial complexity) алгоритма - число операций, которые нужно выполнить при его последовательном исполнении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Пространственная локальность ===&lt;br /&gt;
&#039;&#039;&#039;Пространственная локальность&#039;&#039;&#039; (spatial locality) отражает среднее расстояние между несколькими последовательными обращениями в память.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Производительность ===&lt;br /&gt;
&#039;&#039;&#039;Производительность&#039;&#039;&#039; (performance) &amp;lt;math&amp;gt;R=Op/t&amp;lt;/math&amp;gt; определяется количеством операций &amp;lt;math&amp;gt;Op&amp;lt;/math&amp;gt;, производимых данным компьютером в единицу времени. Для высокопроизводительных вычислений в расчёт обычно берут количество арифметических операций в секунду над вещественными данными, представленными в форме с плавающей точкой. Эта величина называется Flop/s (от английского Floating point operations per second).&lt;br /&gt;
&lt;br /&gt;
Поскольку современные суперкомпьютеры производят очень много таких операций в секунду, их производительность измеряется кратными величинами, такими как GFlop/s (&amp;lt;math&amp;gt;10^9&amp;lt;/math&amp;gt; операций в секунду), TFlop/s (&amp;lt;math&amp;gt;10^{12}&amp;lt;/math&amp;gt;), PFlop/s (&amp;lt;math&amp;gt;10^{15}&amp;lt;/math&amp;gt;), EFlop/s (&amp;lt;math&amp;gt;10^{18}&amp;lt;/math&amp;gt;). Производительность мощнейших современных суперкомпьютеров уже измеряется в EFlop/s, дёт обсуждение построения систем зеттафлопсного (порядка &amp;lt;math&amp;gt;10^{21}&amp;lt;/math&amp;gt; операций в секунду) уровня производительности.&lt;br /&gt;
&lt;br /&gt;
=== Профиль обращений в память ===&lt;br /&gt;
&#039;&#039;&#039;Профиль обращений в память&#039;&#039;&#039; (memory access profile) - последовательность выполняемых в программе обращений к данным в памяти, расположенных в том порядке, в котором обращения происходят в программе.&lt;br /&gt;
&lt;br /&gt;
Обозначим профиль обращений A = {A&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,A&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,…,A&amp;lt;sub&amp;gt;N&amp;lt;/sub&amp;gt;}, где N – общее число всех обращений при выполнении программы. Номер i элемента A&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; в профиле указывает, каким по счету является данное обращение от начала выполнения программы. Любой элемент А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; будем называть элементом профиля. Запись А&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; означает, что данный элемент имеет i-й порядковый номер; данная запись не содержит никакой информации о том, к какой переменной в программе происходит данное обращение.&lt;br /&gt;
&lt;br /&gt;
На данный момент рассматриваются в основном обращения к массивам, поскольку они являются самыми распространенными структурами данных. Каждое обращение представлено в профиле некоторым числом. Таким образом, профиль обращений представляет собой последовательность чисел, которыми могут являться: 1) индексы элементов массива (если профиль строится только для одного массива); 2) виртуальные адреса, к которым происходят обращения; 3) физические адреса. Естественно, в рамках одного профиля используются числа только одного типа.&lt;br /&gt;
&lt;br /&gt;
Подобные профили обращений содержат огромное количество полезной информации о работе программы с памятью. Интересным средством анализа профилей является изучение их визуального представления. Пример визуализации профиля приведен на рис. 2. Ось абсцисс — порядковый номер обращения в память, т. е. чем больше номер, тем позже произошло данное обращение. По оси ординат отложен виртуальный адрес памяти, к которому произошло обращение. Каждая точка — это отдельное обращение в память. &lt;br /&gt;
&lt;br /&gt;
[[file:locality_profile.png|thumb|center|500px|Рисунок 2. Визуализация профиля обращений в память]]&lt;br /&gt;
&lt;br /&gt;
Подобные графики сами по себе могут предоставить интересную информацию о поведении программы. Выделенная на рисунке область 1 (и остальные, аналогичные ей области), скорее всего, обладает хорошей пространственной и временно́й локальностью. Хорошей пространственной — потому что используются только соседние по памяти данные; хорошей временно́й — поскольку повторные обращения к этим данным происходят часто. Область 2 также обладает хорошей пространственной локальностью, поскольку соседние обращения происходят к соседним элементам, однако плохой временно́й локальностью, поскольку повторных обращений к данным просто нет.&lt;br /&gt;
&lt;br /&gt;
Помимо получения данных о локальности, исследование визуализации профилей обращений в память является хорошим средством для понимания и определения шаблонов обращений.&lt;br /&gt;
&lt;br /&gt;
Подобный анализ на основе визуализации профиля обращений помогает понять общее поведение программы, однако он не может дать точной количественной информации о взаимодействии программ с памятью. Для этих целей разрабатываются оценки локальности, такие как [[#Оценка daps|daps]] и [[#Оценка cvg|cvg]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Реальная производительность ===&lt;br /&gt;
&#039;&#039;&#039;Реальная производительность&#039;&#039;&#039; (real performance) &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; — [[#Производительность|производительность]] данного компьютера на конкретном приложении.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Сильная масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Сильная масштабируемость&#039;&#039;&#039; (strong scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи (&amp;lt;math&amp;gt;W=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скошенный параллелизм ===&lt;br /&gt;
&#039;&#039;&#039;Скошенный параллелизм&#039;&#039;&#039; (skewed parallelism) - параллелизм в пространстве итераций, определяемый поверхностями уровней разверток. Ряд исследователей этим термином пользуется только для случая, когда параллелизм не является [[#Координатный паралеллизм|координатным]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Слабая масштабируемость ===&lt;br /&gt;
&#039;&#039;&#039;Слабая масштабируемость&#039;&#039;&#039; (weak scaling) - зависимость [[#Производительность|производительности]] &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; от количества процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; при фиксированной [[#Вычислительная сложность|вычислительной сложности]] задачи в пересчёте на один процессор (&amp;lt;math&amp;gt;W/p=const&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Степень исхода ===&lt;br /&gt;
&#039;&#039;&#039;Степень исхода&#039;&#039;&#039; (degree of a vertex) вершины информационного графа - количество исходящих из данной вершины информационных дуг.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Суперлинейное ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Суперлинейное ускорение&#039;&#039;&#039; (super linear speedup) или &#039;&#039;&#039;сверхлинейное ускорение&#039;&#039;&#039; программы - это [[#Ускорение|ускорение]], превосходящие число используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Чаще всего объясняется эффектом от использования кэш-памяти.&lt;br /&gt;
&lt;br /&gt;
=== Суперскалярность ===&lt;br /&gt;
&#039;&#039;&#039;Суперскалярность&#039;&#039;&#039; — архитектура вычислительного ядра, позволяющая загружать работой множество исполнительных блоков. Планирование исполнения команд является динамическим и осуществляется самим ядром. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Суперскалярность Суперскалярность]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ускорение ===&lt;br /&gt;
&#039;&#039;&#039;Ускорение&#039;&#039;&#039; (speedup) работы программы &amp;lt;math&amp;gt;S = T_1/T_p&amp;lt;/math&amp;gt; - отношение времени работы некоторой программы на одном процессоре &amp;lt;math&amp;gt;T_1&amp;lt;/math&amp;gt; ко времени работы распараллеленной программы при использовании &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; процессоров &amp;lt;math&amp;gt;T_p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&#039;&#039;&#039;Устойчивость&#039;&#039;&#039; (stability) алгоритма - свойство алгоритма не увеличивать или увеличивать в незначительной степени погрешности, допущенной в начальных данных или допускаемой при вычислениях.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное возмущение ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное возмущение&#039;&#039;&#039; (equivalent perturbation) алгоритма - одна из характеристик влияния ошибок округления промежуточных операций на отклонение решения, получаемого алгоритмом, от настоящего решения задачи. Выражается косвенно: влияние ошибок на ответ считается таким же, как если бы данные были заданы с ошибкой, выражаемым эквивалентным возмущением, но задача с такими данными была бы решена точно.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эквивалентное преобразование ===&lt;br /&gt;
&#039;&#039;&#039;Эквивалентное преобразование&#039;&#039;&#039; (equivalent transformaion) программы - такое преобразование, при котором в точности сохраняется результат выполнения программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность распараллеливания ===&lt;br /&gt;
&#039;&#039;&#039;Эффективность распараллеливания&#039;&#039;&#039; (parallel efficiency) &amp;lt;math&amp;gt;E = S/p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; - полученное [[#Ускорение|ускорение]] работы программы, а &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число используемых процессоров) определяет среднюю долю времени выполнения параллельного алгоритма, в течение которого процессоры реально используются для решения задачи. Получение большого ускорения за счёт использования большого числа процессоров зачастую приводит к снижению эффективности.&lt;br /&gt;
&lt;br /&gt;
Если не брать в расчёт эффект [[#Суперлинейное ускорение|суперлинейного ускорения]], то ускорение выполнения программы не превосходит числа используемых процессоров &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;, а значит, эффективность распараллеливания не превосходит единицы. Чем ближе этот показатель к единице, тем лучше для пользователя, поскольку говорит о меньшем количестве накладных расходов, а значит, о лучшем качестве распараллеливания программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Эффективность реализации ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эффективность реализации&#039;&#039;&#039; (implementation efficiency) программы &amp;lt;math&amp;gt;R_{max}/R_{peak}&amp;lt;/math&amp;gt; определяется как отношение [[#Реальная производительность|реальной производительности]] &amp;lt;math&amp;gt;R_{max}&amp;lt;/math&amp;gt; к [[#Пиковая производительность|пиковой производительности]] &amp;lt;math&amp;gt;R_{peak}&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;
&#039;&#039;&#039;Ярусно-параллельная форма (ЯПФ)&#039;&#039;&#039; (parallel form) - это представление графа алгоритма, в котором:&lt;br /&gt;
* все вершины разбиты на перенумерованные подмножества ярусов;&lt;br /&gt;
* начальная вершина каждой дуги расположена на ярусе с номером меньшим, чем номер яруса конечной вершины;&lt;br /&gt;
* между вершинами, расположенными на одном ярусе, не может быть дуг.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Высота&#039;&#039; ЯПФ - это число ярусов.&lt;br /&gt;
Ширина яруса - число вершин, расположенных на ярусе.&lt;br /&gt;
&#039;&#039;Ширина&#039;&#039; ЯПФ - это максимальная ширина ярусов в ЯПФ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Канонической ярусно-параллельной формой&#039;&#039;&#039; называется ЯПФ, высота которой на единицу больше длины критического пути, а все входные вершины расположены на первом ярусе. Для заданного графа его каноническая ЯПФ единственна. Высота канонической ЯПФ соответствует [[#Параллельная сложность|параллельной сложности]] алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;См. также:&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Ярусно-параллельная_форма_графа Ярусно-параллельная форма графа]&#039;&#039;&lt;br /&gt;
* &#039;&#039;[https://ru.wikipedia.org/wiki/Критический_путь_графа Критический путь графа]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[En:Glossary]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Algowiki:Справка]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29726</id>
		<title>Уравнение Пуассона, решение дискретным преобразованием Фурье</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29726"/>
		<updated>2025-02-21T11:20:05Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Уравнение Пуассона, решение дискретным преобразованием Фурье&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Уравнение Пуассона для многомерного пространства имеет вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\partial^2 \phi}{\partial x_i^2}=f,~\mathbf{x}\in D,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D \in \mathbb{R}^N&amp;lt;/math&amp;gt; - область определения решения &amp;lt;math&amp;gt;\phi(\mathbf{x})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathbf{x}=(x_1,...,x_N)^T&amp;lt;/math&amp;gt; - вектор независимых переменных. Уравнение Пуассона дополняется граничными условиями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
B(\phi)=F, \mathbf{x} \in \Gamma(D),&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt; - граница области &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, a &amp;lt;math&amp;gt;B(\phi)&amp;lt;/math&amp;gt; - оператор, определяющий граничные условия. &amp;lt;math&amp;gt;B(\phi)=\phi&amp;lt;/math&amp;gt; соответствует граничным условиям Дирихле, &amp;lt;math&amp;gt;B(\phi)=\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;\mathbf{n}&amp;lt;/math&amp;gt; - внешняя нормаль к границе &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt;) - условиям Неймана. Иногда задают также смешанное граничное условие: &amp;lt;math&amp;gt;B(\phi)=C\phi+\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; - константа). Встречаются также так называемые &amp;quot;периодические граничные условия&amp;quot;, при которых задача ставится для бесконечной области, но предполагается периодичность решения по подмножеству переменных из &amp;lt;math&amp;gt;\mathbf{x}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение Пуассона возникает во многих задачах математической физики, например, в электростатике (в этом случае &amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - потенциал электрической силы) и гидродинамике (&amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - давление жидкости или газа); при этом &amp;lt;math&amp;gt;N=2,3&amp;lt;/math&amp;gt; для плоской и трехмерной задач, соответственно.&lt;br /&gt;
&lt;br /&gt;
Решение уравнения Пуассона для произвольной правой части и неоднородных граничных условий в аналитическом виде неизвестно, поэтому в большинстве приложений оно находится численно. Наиболее распространенная дискретизация этого уравнения имеет вид&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\phi_{k_1,...,k_i+1,...,k_N}-2\phi_{k_1,...,k_i,...,k_N}+\phi_{k_1,...,k_i-1,...,k_N}}{\Delta x_i^2}=f_{k_1,...,k_N},~(k_1,...,k_N) \in D_N. &lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь вторые производные заменены конечно-разностной аппроксимацией второго порядка точности (образуя т.н. схему &amp;quot;крест&amp;quot; для плоской задачи), а решение ищется на дискретном множестве точек &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;-мерного пространства, &amp;lt;math&amp;gt;D_N&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;&lt;br /&gt;
\frac{\phi_{i+1,j,k}-2\phi_{i,j,k}+\phi_{i-1,j,k}}{ \Delta x^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j+1,k}-2\phi_{i,j,k}+\phi_{i,j-1,k}}{ \Delta y^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j,k+1}-2\phi_{i,j,k}+\phi_{i,j,k-1}}{ \Delta z^2} = f_{i,j,k},~(i,j,k) \in D_h,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D_h=\{0:N_x-1\}\times\{0:N_y-1\}\times\{0:N_z-1\} &amp;lt;/math&amp;gt; - параллелепипед в сеточной области. В качестве граничных условий для простоты примем так называемые троякопериодические граничные условия&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
\phi_{0,j,k} &amp;amp;= \phi_{N_x,j,k},\\&lt;br /&gt;
\phi_{i,0,k} &amp;amp;= \phi_{i,N_y,k},\\&lt;br /&gt;
\phi_{i,j,0} &amp;amp;= \phi_{i,j,N_z}.&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Периодические граничные условия удовлетворяются &amp;quot;автоматически&amp;quot;, если представить решение в виде стандартного дискретного обратного преобразования Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x N_y N_z}\sum_{l=0}^{N_x-1}\sum_{m=0}^{N_y-1}\sum_{n=0}^{N_z-1}\Phi_{l,m,n}e^{2\pi \overline{i} &lt;br /&gt;
\left(\frac{il}{N_x}+\frac{jm}{N_y}+\frac{kn}{N_z}\right)}.&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;\overline{i}=\sqrt{-1}&amp;lt;/math&amp;gt;. Аналогичное разложение применяется также к правой части уравнения, &amp;lt;math&amp;gt;f_{i,j,k}&amp;lt;/math&amp;gt;. Решение дискретного уравнения Пуассона преобразованием Фурье удобно тем, что базисные функции разложения Фурье являются собственными функциями дискретного оператора Лапласа. А именно, подставляя разложение Фурье неизвестной функции &amp;lt;math&amp;gt;\phi_{i,j,k}&amp;lt;/math&amp;gt; и правой части в исходное уравнение, получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\Phi_{l,m,n}=-\frac{F_{l,m,n}}{4\left[\sin^2\left(\frac{\pi l}{N_x}\right) + \sin^2\left(\frac{\pi m}{N_y}\right) + \sin^2\left(\frac{\pi n}{N_z}\right) \right]},&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;F_{l,m,n}&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;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x} \sum_{l=0}^{N_x-1} \left[ e^{2\pi \overline{i}\left(\frac{il}{N_x}\right)} &lt;br /&gt;
\frac{1}{N_y} \sum_{m=0}^{N_y-1} \left[ e^{2\pi \overline{i}\left(\frac{jm}{N_y}\right)}&lt;br /&gt;
\frac{1}{N_z} \sum_{n=0}^{N_z-1} \Phi_{l,m,n}e^{2\pi \overline{i} \left(\frac{kn}{N_z}\right)}\right]\right],&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
откуда видно, что трехмерное преобразование Фурье сводится в последовательности трех одномерных. Для вычисления одномерного преобразования широко используется эффективный алгоритм быстрого преобразования Фурье (БПФ, FFT, Fast Fourier Transform)&amp;lt;ref&amp;gt;Марчук Г.И. Методы вычислительной математики, М., 1977, 456с.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Из приведенного выше ясно, что основной макрооперацией алгоритма решения уравнения Пуассона является одномерное быстрое преобразование Фурье. В дальнейшем будем обозначать ее &amp;lt;math&amp;gt;\text{FFT}_i,~i=x,y,z&amp;lt;/math&amp;gt; по каждому из трех направлений, соответственно, а обратное преобразование Фурье - &amp;lt;math&amp;gt;\text{IFFT}_i,~i=x,y,z&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Введем для краткости следующие обозначения сеточных функций:&lt;br /&gt;
&amp;lt;math&amp;gt;\phi_h=\{\phi_{i,j,k},~(i,j,k) \in D_h\},~F_h=\{F_{l,m,n},~l=0,...,N_x-1,~m=0,...,N_y-1,~n=0,...,N_z-1\}&amp;lt;/math&amp;gt; и аналогично &amp;lt;math&amp;gt;f_h&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда алгоритм запишется следующим образом:&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_x(f_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_y(\text{FFT}_x(f_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_z(\text{FFT}_y(\text{FFT}_x(f_h)))=F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Расчет &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_x(\Phi_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_y(\text{IFFT}_x(\Phi_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_z(\text{IFFT}_y(\text{IFFT}_x(\Phi_h)))=\phi_h&amp;lt;/math&amp;gt;&lt;br /&gt;
Примечательно, что весь описанный алгоритм реализуется с помощью одного трехмерного массива &amp;lt;math&amp;gt;N_x \times N_y \times N_z&amp;lt;/math&amp;gt;, поскольку результат каждого одномерного преобразования Фурье можно записать во входной массив и затем использовать его на входе для следующего преобразования, а операция (4) - это поэлементное изменение массива.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма === &lt;br /&gt;
&lt;br /&gt;
Рассмотрим случай куба, &amp;lt;math&amp;gt;N_x=N_y=N_z=N=2^k&amp;lt;/math&amp;gt;. Тогда сложность одномерного БПФ по каждому из направлений составляет (по порядку) &amp;lt;math&amp;gt;N(\text{log}_2 N)&amp;lt;/math&amp;gt; операций. Поскольку одномерное БПФ на каждом из этапов алгоритма, кроме четвертого, осуществляется &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; раз, а количество операций на этапе 4 составляет (снова по порядку) &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;, то общее количество арифметических действий составляет &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Представим информационный граф алгоритма для этапов 1-4, поскольку этапы 5-7 реализуются аналогично этапам 1-3.&lt;br /&gt;
&lt;br /&gt;
[[File:pois3d_graph.png|center|thumb|600px|Зеленые прямоугольники обозначают одномерные сечения входного трехмерного массива. Красным кругом обозначена операция одномерного БПФ, например &amp;lt;math&amp;gt;FFT_{x11}&amp;lt;/math&amp;gt; означает БПФ вдоль оси x при &amp;lt;math&amp;gt;j=1,~k=1&amp;lt;/math&amp;gt;. Желтыми кругами представлены поэлементные преобразования массива для получения коэффициентов Фурье решения (этап 4 алгоритма), например &amp;lt;math&amp;gt;L_{2N,1,...,N}&amp;lt;/math&amp;gt; означает преобразование элементов &amp;lt;math&amp;gt;i=2,~j=N,~k=1,...,N&amp;lt;/math&amp;gt;. Для удобства целочисленные индексы нумеруются числами &amp;lt;math&amp;gt;1,...,N&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;0,...,N-1&amp;lt;/math&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Информационная зависимость между ярусами графа заключается в том, что одномерное БПФ зависит от результата произведенного ранее БПФ по перпендикулярному направлению (т.е. с предыдущего яруса), только если обрабатываемые этими БПФ одномерные сечения массива пересекаются. Следовательно, каждое из БПФ по второй координате, &amp;lt;math&amp;gt;FFT_{i,y,k},~i=1,...,N&amp;lt;/math&amp;gt;, зависит от результатов каждого из БПФ по первой координате &amp;lt;math&amp;gt;FFT_{x,j,k},~j=1,...,N&amp;lt;/math&amp;gt;, и только от них, если эти преобразования производятся в одной плоскости &amp;lt;math&amp;gt;k=K&amp;lt;/math&amp;gt;. Соответственно, каждое БПФ по третьей координате &amp;lt;math&amp;gt;FFT_{i,j,z},~j=1,...,N&amp;lt;/math&amp;gt;, зависит от каждого БПФ по второй координате &amp;lt;math&amp;gt;FFT_{i,y,k},~k=1,...,N&amp;lt;/math&amp;gt;, в одной плоскости &amp;lt;math&amp;gt;i=I&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном выше алгоритме можно выделить, по меньшей мере, два уровня параллелизма. Во-первых, вычисление каждого одномерного БПФ может быть распределено между вычислительными ядрами. И, во-вторых, на каждом этапе алгоритма (ярусе графа) одномерные БПФ независимы друг от друга и также могут быть выполнены паралельно (координатный параллелизм). Для сопоставления параллельной (при координатном распараллеливании) и последовательной сложности алгоритма определим в качестве основных операций одномерное БПФ и поэлементный перерасчет массива (этап 4 алгоритма). Тогда последовательный алгоритм будет состоять из последовательно выполняемых &amp;lt;math&amp;gt;6N^2&amp;lt;/math&amp;gt; одномерных БПФ и &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt; операций над отдельными элементами массива, параллельный же алгоритм будет выполнен за 6 шагов одномерного БПФ и 1 операцию поэлементного преобразования. Если же выразить введенные макрооперации через элементарные арифметические операции, то получим, что сложность последовательного алгоритма - &amp;lt;math&amp;gt;6N^3(\text{log}_2N)+N^3&amp;lt;/math&amp;gt;, а сложность параллельного - &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&amp;lt;/math&amp;gt;. Тогда при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; отношение последовательной сложности к параллельной становится равным &amp;lt;math&amp;gt;\propto N^2(6\text{log}_2N \text{ln}2+\text{ln}2+5)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
В качестве входных данных выступает трехмерный массив &amp;lt;math&amp;gt;N \times N \times N&amp;lt;/math&amp;gt; правой части уравнения. Выходной массив - трехмерный массив решения той же размерности.&lt;br /&gt;
&lt;br /&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;N^3&amp;lt;/math&amp;gt;, вычислительная мощность последовательного алгоритма становится равной &amp;lt;math&amp;gt;6\text{log}_2N+1&amp;lt;/math&amp;gt;, а параллельного алгоритма - &amp;lt;math&amp;gt;(6N\text{log}_2N+1)/N^3 \propto N^{-2}&amp;lt;/math&amp;gt; (при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Приведем пример реализации алгоритма на языке Фортран-90 с применением библиотеки  [http://www.fftw.org/ FFTW]. &lt;br /&gt;
В этом случае трехмерное прямое преобразование Фурье правой части уравнения реализуется как последовательность трех одномерных (этапы 1-3 в п.1.5). &lt;br /&gt;
Полученные коэффициенты Фурье делятся на собственное число оператора Лапласа (этап 4 в п.1.5) (см. комментарии в коде):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workfor_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_x,workfor_x,workfor_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workfor_x(1:i1)) )&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workfor_x(1:i1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_y,workfor_y,workfor_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workfor_y(1:j1)) )&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workfor_y(1:j1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! z - transform and dividing by eigenvalue&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_z,workfor_z,workfor_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workfor_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workfor_z(1:k1)) )&lt;br /&gt;
             ! Dividing by eigenvalue of Laplace operator&lt;br /&gt;
             sinx = sin((i-1) * Pi / i1)^2 * 4&lt;br /&gt;
             siny = sin((j-1) * Pi / j1)^2 * 4&lt;br /&gt;
             do k = 1, k1&lt;br /&gt;
               sinz = sin((k-1) * Pi / k1)^2 * 4&lt;br /&gt;
               f_r(i,j,1:k1) = f_r(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
               f_i(i,j,1:k1) = f_i(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
             enddo&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как только коэффициенты Фурье решения найдены, аналогично производится обратное преобразование Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! inverse x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workback_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_x,workback_x,workback_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workback_x(1:i1)) )/real(i1)&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workback_x(1:i1)) )/real(i1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_y,workback_y,workback_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workback_y(1:j1)) )/real(j1)&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workback_y(1:j1)) )/real(j1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse z - transform&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_z,workback_z,workback_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workback_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workback_z(1:k1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как видим, вложенность циклов соответствует порядку расположения элементов массивов в языке Фортран - по столбцам - это позволяет существенно сократить время обращения к памяти.&lt;br /&gt;
Многократно используются одни и те же вспомогательные массивы, что при небольших размерах сетки должно обеспечить быстроту работы с кэш-памятью. &lt;br /&gt;
Однако, данная реализация не является оптимальной. Так, вместо многократного вызова подпрограммы FFTW_EXECUTE_DFT в циклах, можно было бы обращаться к одной подпрограмме, выполняющей&lt;br /&gt;
заданное множество одномерных БПФ.&lt;br /&gt;
&lt;br /&gt;
Из приведенных выше листингов программы становится очевиден также и ресурс параллелизма алгоритма: каждое одномерное преобразование Фурье выполняется независимо. Самым простым способом использования этого обстоятельства будет вставка соответствующих директив OpenMP перед внутренними циклами - в случае использования многоядерной архтитектуры компьютера на общей памяти. В случае же параллельного выполнения на кластерах с распределенной памятью, необходимо будет позаботиться о распределении входного массива (правой части уравнения) между процессорами, а также &amp;quot;транспозиции&amp;quot; массивов при переходе от БПФ по одному из направлений к БПФ по следующему направлению.&lt;br /&gt;
&lt;br /&gt;
Заметим также, что в приведенной выше реализации для расчета одномерного БПФ производится вызов процедуры библиотеки FFTW, обрабатывающей массив комплексных чисел. В то же время, существует вариант БПФ для преобразования действительных массивов, ускоряющий БПФ в два раза (более подробно см. на [http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data сайте проекта FFTW]).&lt;br /&gt;
&lt;br /&gt;
Важным обстоятельством является то, что большинство вариантов БПФ, включая алгоритм Кули-Тьюки, в арифметике с плавающей запятой имеют очень низкую погрешность.  Верхняя граница относительной ошибки для алгоритма Кули-Тьюки составляет &amp;lt;math&amp;gt;O(\epsilon \log N)&amp;lt;/math&amp;gt; (для сравнения - относительная ошибка преобразования Фурье непосредственно по формуле дискретного преобразования Фурье - &amp;lt;math&amp;gt;O(\epsilon  N^{3/2})&amp;lt;/math&amp;gt;) &amp;lt;ref&amp;gt; Gentleman, W. M.; Sande, G. (1966). &amp;quot;Fast Fourier transforms—for fun and profit&amp;quot;. Proc. AFIPS 29: 563–578. doi:10.1145/1464291.1464352 &amp;lt;/ref&amp;gt;. Поэтому для ускорения алгоритма можно использовать одинарную точность представления переменных без существенного увеличения ошибки.&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
Как было показано выше, существует, по меньшей мере, два уровня параллелизма в описываемом алгоритме. Во-первых, это параллельная реализация одномерных БПФ и, во-вторых, координатный параллелизм - параллельное исполнение независимых одномерных БПФ &amp;lt;ref&amp;gt;Anshu Dubey and Daniele Tessera. Redistribution strategies for portable parallel FFT: a case study. Concurrency and Computation: Practice and Experience, 13(3):209–220, 2001.&amp;lt;/ref&amp;gt;. Эти два уровня могут быть скомбинированы, например, путем распределения разных БПФ между MPI-процессами, а каждого отдельного БПФ - между нитями на общей памяти (POSIX, OpenMP, и т.д.). Ниже мы приведем детали базового алгоритма распараллеливания с использованием координатного параллелизма, рассмотрим его недостатки и перечислим возможные способы повышения его масштабируемости.&lt;br /&gt;
&lt;br /&gt;
Координатный параллелизм в контексте данной задачи реализуется в результате разбиения трехмерной области на подобласти, в каждой из которых можно независимо от расчетов в других подобластях, выполнить одномерные БПФ. К настоящему времени предложены две реализации такого подхода: одномерное разбиение области (slab decomposition) и двумерное разбиение (pencil decomposition) &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;. При одномерном разбиении требуется меньшее количество MPI-пересылок, однако, максимальное количество процессоров/ядер ограничено максимальным по трем измерениям размером области. Поэтому с точки зрения массивного параллелизма двумерная декомпозиция предпочтительнее, и ниже мы остановимся на этом подходе.&lt;br /&gt;
&lt;br /&gt;
При MPI-реализации необходимо принять во внимание накладные расходы, вызванные пересылками данных между процессорами. Для реализации обсуждаемого алгоритма необходимо осуществлять т.н. транспонирования массивов, при которых на каждом из трех этапов преобразования Фурье (этапы 1-3 и 5-7 в п.1.5) обеспечивается нахождение элементов массива вдоль соответствующих направлений в памяти соответствующих процессоров:&lt;br /&gt;
&lt;br /&gt;
[[File:transp.png|center|thumb|800px|Транспонирование трехмерного массива при параллельной реализации трехмерного БПФ]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим соотношение вычислений и пересылок данных при MPI-реализации. Вычислительная сложность алгоритма при покоординатном распараллеливании, при запуске на &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; MPI-процессах составляет  &amp;lt;math&amp;gt; \left(6N^3(\log_2 N) + N^3\right)/M&amp;lt;/math&amp;gt;, т.е., в лучшем случае, &amp;lt;math&amp;gt; 6N(\log_2 N) + N&amp;lt;/math&amp;gt; (на &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; процессах). При этом, суммарное количество отсылаемых и получаемых MPI-пакетов составляет &amp;lt;math&amp;gt;8N_{px}+4N_{py}&amp;lt;/math&amp;gt;, а суммарное количество отсылаемых и получаемых элементов массива на каждом процессе - &amp;lt;math&amp;gt;12N^3/(N_{px}N_{py})&amp;lt;/math&amp;gt; (здесь - &amp;lt;math&amp;gt;N_{px},~N_{py}&amp;lt;/math&amp;gt; - количества процессов в двумерной MPI-декомпозиции области по осям &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;, соответственно - см. рис. выше). Учитывая, что &amp;lt;math&amp;gt;M=N_{px}N_{py}&amp;lt;/math&amp;gt;, получаем, что отношение количества пересылаемых элементов массива к количеству арифметических операций составляет &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N + 1)&amp;lt;/math&amp;gt;. Таким образом, отношение объема пересылаемых элементов к количеству операций не зависит от количества MPI-процессов и уменьшается с ростом размера задачи. При больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, однако, эта зависимость становится слабой, т.е. &amp;quot;насыщается&amp;quot;. В то же время, при фиксированном размере задачи, рост количества используемых процессов, не изменяя параметра &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;, вызывает рост числа пакетов (&amp;lt;math&amp;gt;\propto \sqrt{M}&amp;lt;/math&amp;gt;, в силу &amp;lt;math&amp;gt;N_{px} \propto N_{py} \propto \sqrt{M}&amp;lt;/math&amp;gt; и формул, приведенных выше). В силу латентности сети, это приводит к росту времени пересылки единицы данных и, следовательно, замедлению ускорения алгоритма. &lt;br /&gt;
&lt;br /&gt;
Приведенный здесь анализ может служить только для ориентировочных оценок, поскольку он не дает времен вычислений и MPI-обменов. Более детальные расчеты для случаев одномерной и двумерной декомпозиции области обширно представлены в литературе &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;P. Dmitruk, L.-P. Wang, W.H. Matthaeus, R. Zhang, D. Seckel, Scalable parallel FFT for spectral simulations on a Beowulf cluster, Parallel Comput. 27&lt;br /&gt;
(2001) 1921–1936.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В профилируемом в следующих разделах программном коде параллельной реализации алгоритма вызовы одномерных БПФ по трем направлениям, показанные в листинге п.2.1, перемежаются вызовами специальных процедур, осуществляющих транспонирование массива. Отдельно транспонируются действительная и мнимая части массива (что уже не оптимально - лучше пересылать комплексные числа) с помощью коммуникаций &amp;quot;точка-точка&amp;quot;. При этом используются асинхронные пересылки с помощью MPI_ISEND и MPI_IRECV.&lt;br /&gt;
&lt;br /&gt;
=== Результаты прогонов ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29725</id>
		<title>Уравнение Пуассона, решение дискретным преобразованием Фурье</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29725"/>
		<updated>2025-02-21T11:18:44Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Уравнение Пуассона, решение дискретным преобразованием Фурье&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&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^3&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Уравнение Пуассона для многомерного пространства имеет вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\partial^2 \phi}{\partial x_i^2}=f,~\mathbf{x}\in D,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D \in \mathbb{R}^N&amp;lt;/math&amp;gt; - область определения решения &amp;lt;math&amp;gt;\phi(\mathbf{x})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathbf{x}=(x_1,...,x_N)^T&amp;lt;/math&amp;gt; - вектор независимых переменных. Уравнение Пуассона дополняется граничными условиями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
B(\phi)=F, \mathbf{x} \in \Gamma(D),&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt; - граница области &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, a &amp;lt;math&amp;gt;B(\phi)&amp;lt;/math&amp;gt; - оператор, определяющий граничные условия. &amp;lt;math&amp;gt;B(\phi)=\phi&amp;lt;/math&amp;gt; соответствует граничным условиям Дирихле, &amp;lt;math&amp;gt;B(\phi)=\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;\mathbf{n}&amp;lt;/math&amp;gt; - внешняя нормаль к границе &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt;) - условиям Неймана. Иногда задают также смешанное граничное условие: &amp;lt;math&amp;gt;B(\phi)=C\phi+\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; - константа). Встречаются также так называемые &amp;quot;периодические граничные условия&amp;quot;, при которых задача ставится для бесконечной области, но предполагается периодичность решения по подмножеству переменных из &amp;lt;math&amp;gt;\mathbf{x}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение Пуассона возникает во многих задачах математической физики, например, в электростатике (в этом случае &amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - потенциал электрической силы) и гидродинамике (&amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - давление жидкости или газа); при этом &amp;lt;math&amp;gt;N=2,3&amp;lt;/math&amp;gt; для плоской и трехмерной задач, соответственно.&lt;br /&gt;
&lt;br /&gt;
Решение уравнения Пуассона для произвольной правой части и неоднородных граничных условий в аналитическом виде неизвестно, поэтому в большинстве приложений оно находится численно. Наиболее распространенная дискретизация этого уравнения имеет вид&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\phi_{k_1,...,k_i+1,...,k_N}-2\phi_{k_1,...,k_i,...,k_N}+\phi_{k_1,...,k_i-1,...,k_N}}{\Delta x_i^2}=f_{k_1,...,k_N},~(k_1,...,k_N) \in D_N. &lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь вторые производные заменены конечно-разностной аппроксимацией второго порядка точности (образуя т.н. схему &amp;quot;крест&amp;quot; для плоской задачи), а решение ищется на дискретном множестве точек &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;-мерного пространства, &amp;lt;math&amp;gt;D_N&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;&lt;br /&gt;
\frac{\phi_{i+1,j,k}-2\phi_{i,j,k}+\phi_{i-1,j,k}}{ \Delta x^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j+1,k}-2\phi_{i,j,k}+\phi_{i,j-1,k}}{ \Delta y^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j,k+1}-2\phi_{i,j,k}+\phi_{i,j,k-1}}{ \Delta z^2} = f_{i,j,k},~(i,j,k) \in D_h,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D_h=\{0:N_x-1\}\times\{0:N_y-1\}\times\{0:N_z-1\} &amp;lt;/math&amp;gt; - параллелепипед в сеточной области. В качестве граничных условий для простоты примем так называемые троякопериодические граничные условия&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
\phi_{0,j,k} &amp;amp;= \phi_{N_x,j,k},\\&lt;br /&gt;
\phi_{i,0,k} &amp;amp;= \phi_{i,N_y,k},\\&lt;br /&gt;
\phi_{i,j,0} &amp;amp;= \phi_{i,j,N_z}.&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Периодические граничные условия удовлетворяются &amp;quot;автоматически&amp;quot;, если представить решение в виде стандартного дискретного обратного преобразования Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x N_y N_z}\sum_{l=0}^{N_x-1}\sum_{m=0}^{N_y-1}\sum_{n=0}^{N_z-1}\Phi_{l,m,n}e^{2\pi \overline{i} &lt;br /&gt;
\left(\frac{il}{N_x}+\frac{jm}{N_y}+\frac{kn}{N_z}\right)}.&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;\overline{i}=\sqrt{-1}&amp;lt;/math&amp;gt;. Аналогичное разложение применяется также к правой части уравнения, &amp;lt;math&amp;gt;f_{i,j,k}&amp;lt;/math&amp;gt;. Решение дискретного уравнения Пуассона преобразованием Фурье удобно тем, что базисные функции разложения Фурье являются собственными функциями дискретного оператора Лапласа. А именно, подставляя разложение Фурье неизвестной функции &amp;lt;math&amp;gt;\phi_{i,j,k}&amp;lt;/math&amp;gt; и правой части в исходное уравнение, получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\Phi_{l,m,n}=-\frac{F_{l,m,n}}{4\left[\sin^2\left(\frac{\pi l}{N_x}\right) + \sin^2\left(\frac{\pi m}{N_y}\right) + \sin^2\left(\frac{\pi n}{N_z}\right) \right]},&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;F_{l,m,n}&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;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x} \sum_{l=0}^{N_x-1} \left[ e^{2\pi \overline{i}\left(\frac{il}{N_x}\right)} &lt;br /&gt;
\frac{1}{N_y} \sum_{m=0}^{N_y-1} \left[ e^{2\pi \overline{i}\left(\frac{jm}{N_y}\right)}&lt;br /&gt;
\frac{1}{N_z} \sum_{n=0}^{N_z-1} \Phi_{l,m,n}e^{2\pi \overline{i} \left(\frac{kn}{N_z}\right)}\right]\right],&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
откуда видно, что трехмерное преобразование Фурье сводится в последовательности трех одномерных. Для вычисления одномерного преобразования широко используется эффективный алгоритм быстрого преобразования Фурье (БПФ, FFT, Fast Fourier Transform)&amp;lt;ref&amp;gt;Марчук Г.И. Методы вычислительной математики, М., 1977, 456с.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Из приведенного выше ясно, что основной макрооперацией алгоритма решения уравнения Пуассона является одномерное быстрое преобразование Фурье. В дальнейшем будем обозначать ее &amp;lt;math&amp;gt;\text{FFT}_i,~i=x,y,z&amp;lt;/math&amp;gt; по каждому из трех направлений, соответственно, а обратное преобразование Фурье - &amp;lt;math&amp;gt;\text{IFFT}_i,~i=x,y,z&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Введем для краткости следующие обозначения сеточных функций:&lt;br /&gt;
&amp;lt;math&amp;gt;\phi_h=\{\phi_{i,j,k},~(i,j,k) \in D_h\},~F_h=\{F_{l,m,n},~l=0,...,N_x-1,~m=0,...,N_y-1,~n=0,...,N_z-1\}&amp;lt;/math&amp;gt; и аналогично &amp;lt;math&amp;gt;f_h&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда алгоритм запишется следующим образом:&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_x(f_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_y(\text{FFT}_x(f_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_z(\text{FFT}_y(\text{FFT}_x(f_h)))=F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Расчет &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_x(\Phi_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_y(\text{IFFT}_x(\Phi_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_z(\text{IFFT}_y(\text{IFFT}_x(\Phi_h)))=\phi_h&amp;lt;/math&amp;gt;&lt;br /&gt;
Примечательно, что весь описанный алгоритм реализуется с помощью одного трехмерного массива &amp;lt;math&amp;gt;N_x \times N_y \times N_z&amp;lt;/math&amp;gt;, поскольку результат каждого одномерного преобразования Фурье можно записать во входной массив и затем использовать его на входе для следующего преобразования, а операция (4) - это поэлементное изменение массива.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма === &lt;br /&gt;
&lt;br /&gt;
Рассмотрим случай куба, &amp;lt;math&amp;gt;N_x=N_y=N_z=N=2^k&amp;lt;/math&amp;gt;. Тогда сложность одномерного БПФ по каждому из направлений составляет (по порядку) &amp;lt;math&amp;gt;N(\text{log}_2 N)&amp;lt;/math&amp;gt; операций. Поскольку одномерное БПФ на каждом из этапов алгоритма, кроме четвертого, осуществляется &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; раз, а количество операций на этапе 4 составляет (снова по порядку) &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;, то общее количество арифметических действий составляет &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Представим информационный граф алгоритма для этапов 1-4, поскольку этапы 5-7 реализуются аналогично этапам 1-3.&lt;br /&gt;
&lt;br /&gt;
[[File:pois3d_graph.png|center|thumb|600px|Зеленые прямоугольники обозначают одномерные сечения входного трехмерного массива. Красным кругом обозначена операция одномерного БПФ, например &amp;lt;math&amp;gt;FFT_{x11}&amp;lt;/math&amp;gt; означает БПФ вдоль оси x при &amp;lt;math&amp;gt;j=1,~k=1&amp;lt;/math&amp;gt;. Желтыми кругами представлены поэлементные преобразования массива для получения коэффициентов Фурье решения (этап 4 алгоритма), например &amp;lt;math&amp;gt;L_{2N,1,...,N}&amp;lt;/math&amp;gt; означает преобразование элементов &amp;lt;math&amp;gt;i=2,~j=N,~k=1,...,N&amp;lt;/math&amp;gt;. Для удобства целочисленные индексы нумеруются числами &amp;lt;math&amp;gt;1,...,N&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;0,...,N-1&amp;lt;/math&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Информационная зависимость между ярусами графа заключается в том, что одномерное БПФ зависит от результата произведенного ранее БПФ по перпендикулярному направлению (т.е. с предыдущего яруса), только если обрабатываемые этими БПФ одномерные сечения массива пересекаются. Следовательно, каждое из БПФ по второй координате, &amp;lt;math&amp;gt;FFT_{i,y,k},~i=1,...,N&amp;lt;/math&amp;gt;, зависит от результатов каждого из БПФ по первой координате &amp;lt;math&amp;gt;FFT_{x,j,k},~j=1,...,N&amp;lt;/math&amp;gt;, и только от них, если эти преобразования производятся в одной плоскости &amp;lt;math&amp;gt;k=K&amp;lt;/math&amp;gt;. Соответственно, каждое БПФ по третьей координате &amp;lt;math&amp;gt;FFT_{i,j,z},~j=1,...,N&amp;lt;/math&amp;gt;, зависит от каждого БПФ по второй координате &amp;lt;math&amp;gt;FFT_{i,y,k},~k=1,...,N&amp;lt;/math&amp;gt;, в одной плоскости &amp;lt;math&amp;gt;i=I&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном выше алгоритме можно выделить, по меньшей мере, два уровня параллелизма. Во-первых, вычисление каждого одномерного БПФ может быть распределено между вычислительными ядрами. И, во-вторых, на каждом этапе алгоритма (ярусе графа) одномерные БПФ независимы друг от друга и также могут быть выполнены паралельно (координатный параллелизм). Для сопоставления параллельной (при координатном распараллеливании) и последовательной сложности алгоритма определим в качестве основных операций одномерное БПФ и поэлементный перерасчет массива (этап 4 алгоритма). Тогда последовательный алгоритм будет состоять из последовательно выполняемых &amp;lt;math&amp;gt;6N^2&amp;lt;/math&amp;gt; одномерных БПФ и &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt; операций над отдельными элементами массива, параллельный же алгоритм будет выполнен за 6 шагов одномерного БПФ и 1 операцию поэлементного преобразования. Если же выразить введенные макрооперации через элементарные арифметические операции, то получим, что сложность последовательного алгоритма - &amp;lt;math&amp;gt;6N^3(\text{log}_2N)+N^3&amp;lt;/math&amp;gt;, а сложность параллельного - &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&amp;lt;/math&amp;gt;. Тогда при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; отношение последовательной сложности к параллельной становится равным &amp;lt;math&amp;gt;\propto N^2(6\text{log}_2N \text{ln}2+\text{ln}2+5)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
В качестве входных данных выступает трехмерный массив &amp;lt;math&amp;gt;N \times N \times N&amp;lt;/math&amp;gt; правой части уравнения. Выходной массив - трехмерный массив решения той же размерности.&lt;br /&gt;
&lt;br /&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;N^3&amp;lt;/math&amp;gt;, вычислительная мощность последовательного алгоритма становится равной &amp;lt;math&amp;gt;6\text{log}_2N+1&amp;lt;/math&amp;gt;, а параллельного алгоритма - &amp;lt;math&amp;gt;(6N\text{log}_2N+1)/N^3 \propto N^{-2}&amp;lt;/math&amp;gt; (при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Приведем пример реализации алгоритма на языке Фортран-90 с применением библиотеки  [http://www.fftw.org/ FFTW]. &lt;br /&gt;
В этом случае трехмерное прямое преобразование Фурье правой части уравнения реализуется как последовательность трех одномерных (этапы 1-3 в п.1.5). &lt;br /&gt;
Полученные коэффициенты Фурье делятся на собственное число оператора Лапласа (этап 4 в п.1.5) (см. комментарии в коде):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workfor_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_x,workfor_x,workfor_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workfor_x(1:i1)) )&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workfor_x(1:i1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_y,workfor_y,workfor_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workfor_y(1:j1)) )&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workfor_y(1:j1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! z - transform and dividing by eigenvalue&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_z,workfor_z,workfor_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workfor_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workfor_z(1:k1)) )&lt;br /&gt;
             ! Dividing by eigenvalue of Laplace operator&lt;br /&gt;
             sinx = sin((i-1) * Pi / i1)^2 * 4&lt;br /&gt;
             siny = sin((j-1) * Pi / j1)^2 * 4&lt;br /&gt;
             do k = 1, k1&lt;br /&gt;
               sinz = sin((k-1) * Pi / k1)^2 * 4&lt;br /&gt;
               f_r(i,j,1:k1) = f_r(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
               f_i(i,j,1:k1) = f_i(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
             enddo&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как только коэффициенты Фурье решения найдены, аналогично производится обратное преобразование Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! inverse x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workback_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_x,workback_x,workback_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workback_x(1:i1)) )/real(i1)&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workback_x(1:i1)) )/real(i1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_y,workback_y,workback_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workback_y(1:j1)) )/real(j1)&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workback_y(1:j1)) )/real(j1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse z - transform&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_z,workback_z,workback_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workback_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workback_z(1:k1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как видим, вложенность циклов соответствует порядку расположения элементов массивов в языке Фортран - по столбцам - это позволяет существенно сократить время обращения к памяти.&lt;br /&gt;
Многократно используются одни и те же вспомогательные массивы, что при небольших размерах сетки должно обеспечить быстроту работы с кэш-памятью. &lt;br /&gt;
Однако, данная реализация не является оптимальной. Так, вместо многократного вызова подпрограммы FFTW_EXECUTE_DFT в циклах, можно было бы обращаться к одной подпрограмме, выполняющей&lt;br /&gt;
заданное множество одномерных БПФ.&lt;br /&gt;
&lt;br /&gt;
Из приведенных выше листингов программы становится очевиден также и ресурс параллелизма алгоритма: каждое одномерное преобразование Фурье выполняется независимо. Самым простым способом использования этого обстоятельства будет вставка соответствующих директив OpenMP перед внутренними циклами - в случае использования многоядерной архтитектуры компьютера на общей памяти. В случае же параллельного выполнения на кластерах с распределенной памятью, необходимо будет позаботиться о распределении входного массива (правой части уравнения) между процессорами, а также &amp;quot;транспозиции&amp;quot; массивов при переходе от БПФ по одному из направлений к БПФ по следующему направлению.&lt;br /&gt;
&lt;br /&gt;
Заметим также, что в приведенной выше реализации для расчета одномерного БПФ производится вызов процедуры библиотеки FFTW, обрабатывающей массив комплексных чисел. В то же время, существует вариант БПФ для преобразования действительных массивов, ускоряющий БПФ в два раза (более подробно см. на [http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data сайте проекта FFTW]).&lt;br /&gt;
&lt;br /&gt;
Важным обстоятельством является то, что большинство вариантов БПФ, включая алгоритм Кули-Тьюки, в арифметике с плавающей запятой имеют очень низкую погрешность.  Верхняя граница относительной ошибки для алгоритма Кули-Тьюки составляет &amp;lt;math&amp;gt;O(\epsilon \log N)&amp;lt;/math&amp;gt; (для сравнения - относительная ошибка преобразования Фурье непосредственно по формуле дискретного преобразования Фурье - &amp;lt;math&amp;gt;O(\epsilon  N^{3/2})&amp;lt;/math&amp;gt;) &amp;lt;ref&amp;gt; Gentleman, W. M.; Sande, G. (1966). &amp;quot;Fast Fourier transforms—for fun and profit&amp;quot;. Proc. AFIPS 29: 563–578. doi:10.1145/1464291.1464352 &amp;lt;/ref&amp;gt;. Поэтому для ускорения алгоритма можно использовать одинарную точность представления переменных без существенного увеличения ошибки.&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
Как было показано выше, существует, по меньшей мере, два уровня параллелизма в описываемом алгоритме. Во-первых, это параллельная реализация одномерных БПФ и, во-вторых, координатный параллелизм - параллельное исполнение независимых одномерных БПФ &amp;lt;ref&amp;gt;Anshu Dubey and Daniele Tessera. Redistribution strategies for portable parallel FFT: a case study. Concurrency and Computation: Practice and Experience, 13(3):209–220, 2001.&amp;lt;/ref&amp;gt;. Эти два уровня могут быть скомбинированы, например, путем распределения разных БПФ между MPI-процессами, а каждого отдельного БПФ - между нитями на общей памяти (POSIX, OpenMP, и т.д.). Ниже мы приведем детали базового алгоритма распараллеливания с использованием координатного параллелизма, рассмотрим его недостатки и перечислим возможные способы повышения его масштабируемости.&lt;br /&gt;
&lt;br /&gt;
Координатный параллелизм в контексте данной задачи реализуется в результате разбиения трехмерной области на подобласти, в каждой из которых можно независимо от расчетов в других подобластях, выполнить одномерные БПФ. К настоящему времени предложены две реализации такого подхода: одномерное разбиение области (slab decomposition) и двумерное разбиение (pencil decomposition) &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;. При одномерном разбиении требуется меньшее количество MPI-пересылок, однако, максимальное количество процессоров/ядер ограничено максимальным по трем измерениям размером области. Поэтому с точки зрения массивного параллелизма двумерная декомпозиция предпочтительнее, и ниже мы остановимся на этом подходе.&lt;br /&gt;
&lt;br /&gt;
При MPI-реализации необходимо принять во внимание накладные расходы, вызванные пересылками данных между процессорами. Для реализации обсуждаемого алгоритма необходимо осуществлять т.н. транспонирования массивов, при которых на каждом из трех этапов преобразования Фурье (этапы 1-3 и 5-7 в п.1.5) обеспечивается нахождение элементов массива вдоль соответствующих направлений в памяти соответствующих процессоров:&lt;br /&gt;
&lt;br /&gt;
[[File:transp.png|center|thumb|800px|Транспонирование трехмерного массива при параллельной реализации трехмерного БПФ]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим соотношение вычислений и пересылок данных при MPI-реализации. Вычислительная сложность алгоритма при покоординатном распараллеливании, при запуске на &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; MPI-процессах составляет  &amp;lt;math&amp;gt; \left(6N^3(\log_2 N) + N^3\right)/M&amp;lt;/math&amp;gt;, т.е., в лучшем случае, &amp;lt;math&amp;gt; 6N(\log_2 N) + N&amp;lt;/math&amp;gt; (на &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; процессах). При этом, суммарное количество отсылаемых и получаемых MPI-пакетов составляет &amp;lt;math&amp;gt;8N_{px}+4N_{py}&amp;lt;/math&amp;gt;, а суммарное количество отсылаемых и получаемых элементов массива на каждом процессе - &amp;lt;math&amp;gt;12N^3/(N_{px}N_{py})&amp;lt;/math&amp;gt; (здесь - &amp;lt;math&amp;gt;N_{px},~N_{py}&amp;lt;/math&amp;gt; - количества процессов в двумерной MPI-декомпозиции области по осям &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;, соответственно - см. рис. выше). Учитывая, что &amp;lt;math&amp;gt;M=N_{px}N_{py}&amp;lt;/math&amp;gt;, получаем, что отношение количества пересылаемых элементов массива к количеству арифметических операций составляет &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N + 1)&amp;lt;/math&amp;gt;. Таким образом, отношение объема пересылаемых элементов к количеству операций не зависит от количества MPI-процессов и уменьшается с ростом размера задачи. При больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, однако, эта зависимость становится слабой, т.е. &amp;quot;насыщается&amp;quot;. В то же время, при фиксированном размере задачи, рост количества используемых процессов, не изменяя параметра &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;, вызывает рост числа пакетов (&amp;lt;math&amp;gt;\propto \sqrt{M}&amp;lt;/math&amp;gt;, в силу &amp;lt;math&amp;gt;N_{px} \propto N_{py} \propto \sqrt{M}&amp;lt;/math&amp;gt; и формул, приведенных выше). В силу латентности сети, это приводит к росту времени пересылки единицы данных и, следовательно, замедлению ускорения алгоритма. &lt;br /&gt;
&lt;br /&gt;
Приведенный здесь анализ может служить только для ориентировочных оценок, поскольку он не дает времен вычислений и MPI-обменов. Более детальные расчеты для случаев одномерной и двумерной декомпозиции области обширно представлены в литературе &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;P. Dmitruk, L.-P. Wang, W.H. Matthaeus, R. Zhang, D. Seckel, Scalable parallel FFT for spectral simulations on a Beowulf cluster, Parallel Comput. 27&lt;br /&gt;
(2001) 1921–1936.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В профилируемом в следующих разделах программном коде параллельной реализации алгоритма вызовы одномерных БПФ по трем направлениям, показанные в листинге п.2.1, перемежаются вызовами специальных процедур, осуществляющих транспонирование массива. Отдельно транспонируются действительная и мнимая части массива (что уже не оптимально - лучше пересылать комплексные числа) с помощью коммуникаций &amp;quot;точка-точка&amp;quot;. При этом используются асинхронные пересылки с помощью MPI_ISEND и MPI_IRECV.&lt;br /&gt;
&lt;br /&gt;
=== Результаты прогонов ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29724</id>
		<title>Уравнение Пуассона, решение дискретным преобразованием Фурье</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29724"/>
		<updated>2025-02-21T11:18:11Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Уравнение Пуассона, решение дискретным преобразованием Фурье&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&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^3&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Уравнение Пуассона для многомерного пространства имеет вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\partial^2 \phi}{\partial x_i^2}=f,~\mathbf{x}\in D,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D \in \mathbb{R}^N&amp;lt;/math&amp;gt; - область определения решения &amp;lt;math&amp;gt;\phi(\mathbf{x})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathbf{x}=(x_1,...,x_N)^T&amp;lt;/math&amp;gt; - вектор независимых переменных. Уравнение Пуассона дополняется граничными условиями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
B(\phi)=F, \mathbf{x} \in \Gamma(D),&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt; - граница области &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, a &amp;lt;math&amp;gt;B(\phi)&amp;lt;/math&amp;gt; - оператор, определяющий граничные условия. &amp;lt;math&amp;gt;B(\phi)=\phi&amp;lt;/math&amp;gt; соответствует граничным условиям Дирихле, &amp;lt;math&amp;gt;B(\phi)=\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;\mathbf{n}&amp;lt;/math&amp;gt; - внешняя нормаль к границе &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt;) - условиям Неймана. Иногда задают также смешанное граничное условие: &amp;lt;math&amp;gt;B(\phi)=C\phi+\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; - константа). Встречаются также так называемые &amp;quot;периодические граничные условия&amp;quot;, при которых задача ставится для бесконечной области, но предполагается периодичность решения по подмножеству переменных из &amp;lt;math&amp;gt;\mathbf{x}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение Пуассона возникает во многих задачах математической физики, например, в электростатике (в этом случае &amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - потенциал электрической силы) и гидродинамике (&amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - давление жидкости или газа); при этом &amp;lt;math&amp;gt;N=2,3&amp;lt;/math&amp;gt; для плоской и трехмерной задач, соответственно.&lt;br /&gt;
&lt;br /&gt;
Решение уравнения Пуассона для произвольной правой части и неоднородных граничных условий в аналитическом виде неизвестно, поэтому в большинстве приложений оно находится численно. Наиболее распространенная дискретизация этого уравнения имеет вид&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\phi_{k_1,...,k_i+1,...,k_N}-2\phi_{k_1,...,k_i,...,k_N}+\phi_{k_1,...,k_i-1,...,k_N}}{\Delta x_i^2}=f_{k_1,...,k_N},~(k_1,...,k_N) \in D_N. &lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь вторые производные заменены конечно-разностной аппроксимацией второго порядка точности (образуя т.н. схему &amp;quot;крест&amp;quot; для плоской задачи), а решение ищется на дискретном множестве точек &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;-мерного пространства, &amp;lt;math&amp;gt;D_N&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;&lt;br /&gt;
\frac{\phi_{i+1,j,k}-2\phi_{i,j,k}+\phi_{i-1,j,k}}{ \Delta x^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j+1,k}-2\phi_{i,j,k}+\phi_{i,j-1,k}}{ \Delta y^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j,k+1}-2\phi_{i,j,k}+\phi_{i,j,k-1}}{ \Delta z^2} = f_{i,j,k},~(i,j,k) \in D_h,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D_h=\{0:N_x-1\}\times\{0:N_y-1\}\times\{0:N_z-1\} &amp;lt;/math&amp;gt; - параллелепипед в сеточной области. В качестве граничных условий для простоты примем так называемые троякопериодические граничные условия&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
\phi_{0,j,k} &amp;amp;= \phi_{N_x,j,k},\\&lt;br /&gt;
\phi_{i,0,k} &amp;amp;= \phi_{i,N_y,k},\\&lt;br /&gt;
\phi_{i,j,0} &amp;amp;= \phi_{i,j,N_z}.&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Периодические граничные условия удовлетворяются &amp;quot;автоматически&amp;quot;, если представить решение в виде стандартного дискретного обратного преобразования Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x N_y N_z}\sum_{l=0}^{N_x-1}\sum_{m=0}^{N_y-1}\sum_{n=0}^{N_z-1}\Phi_{l,m,n}e^{2\pi \overline{i} &lt;br /&gt;
\left(\frac{il}{N_x}+\frac{jm}{N_y}+\frac{kn}{N_z}\right)}.&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;\overline{i}=\sqrt{-1}&amp;lt;/math&amp;gt;. Аналогичное разложение применяется также к правой части уравнения, &amp;lt;math&amp;gt;f_{i,j,k}&amp;lt;/math&amp;gt;. Решение дискретного уравнения Пуассона преобразованием Фурье удобно тем, что базисные функции разложения Фурье являются собственными функциями дискретного оператора Лапласа. А именно, подставляя разложение Фурье неизвестной функции &amp;lt;math&amp;gt;\phi_{i,j,k}&amp;lt;/math&amp;gt; и правой части в исходное уравнение, получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\Phi_{l,m,n}=-\frac{F_{l,m,n}}{4\left[\sin^2\left(\frac{\pi l}{N_x}\right) + \sin^2\left(\frac{\pi m}{N_y}\right) + \sin^2\left(\frac{\pi n}{N_z}\right) \right]},&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;F_{l,m,n}&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;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x} \sum_{l=0}^{N_x-1} \left[ e^{2\pi \overline{i}\left(\frac{il}{N_x}\right)} &lt;br /&gt;
\frac{1}{N_y} \sum_{m=0}^{N_y-1} \left[ e^{2\pi \overline{i}\left(\frac{jm}{N_y}\right)}&lt;br /&gt;
\frac{1}{N_z} \sum_{n=0}^{N_z-1} \Phi_{l,m,n}e^{2\pi \overline{i} \left(\frac{kn}{N_z}\right)}\right]\right],&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
откуда видно, что трехмерное преобразование Фурье сводится в последовательности трех одномерных. Для вычисления одномерного преобразования широко используется эффективный алгоритм быстрого преобразования Фурье (БПФ, FFT, Fast Fourier Transform)&amp;lt;ref&amp;gt;Марчук Г.И. Методы вычислительной математики, М., 1977, 456с.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Из приведенного выше ясно, что основной макрооперацией алгоритма решения уравнения Пуассона является одномерное быстрое преобразование Фурье. В дальнейшем будем обозначать ее &amp;lt;math&amp;gt;\text{FFT}_i,~i=x,y,z&amp;lt;/math&amp;gt; по каждому из трех направлений, соответственно, а обратное преобразование Фурье - &amp;lt;math&amp;gt;\text{IFFT}_i,~i=x,y,z&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Введем для краткости следующие обозначения сеточных функций:&lt;br /&gt;
&amp;lt;math&amp;gt;\phi_h=\{\phi_{i,j,k},~(i,j,k) \in D_h\},~F_h=\{F_{l,m,n},~l=0,...,N_x-1,~m=0,...,N_y-1,~n=0,...,N_z-1\}&amp;lt;/math&amp;gt; и аналогично &amp;lt;math&amp;gt;f_h&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда алгоритм запишется следующим образом:&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_x(f_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_y(\text{FFT}_x(f_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_z(\text{FFT}_y(\text{FFT}_x(f_h)))=F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Расчет &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_x(\Phi_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_y(\text{IFFT}_x(\Phi_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_z(\text{IFFT}_y(\text{IFFT}_x(\Phi_h)))=\phi_h&amp;lt;/math&amp;gt;&lt;br /&gt;
Примечательно, что весь описанный алгоритм реализуется с помощью одного трехмерного массива &amp;lt;math&amp;gt;N_x \times N_y \times N_z&amp;lt;/math&amp;gt;, поскольку результат каждого одномерного преобразования Фурье можно записать во входной массив и затем использовать его на входе для следующего преобразования, а операция (4) - это поэлементное изменение массива.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма === &lt;br /&gt;
&lt;br /&gt;
Рассмотрим случай куба, &amp;lt;math&amp;gt;N_x=N_y=N_z=N=2^k&amp;lt;/math&amp;gt;. Тогда сложность одномерного БПФ по каждому из направлений составляет (по порядку) &amp;lt;math&amp;gt;N(\text{log}_2 N)&amp;lt;/math&amp;gt; операций. Поскольку одномерное БПФ на каждом из этапов алгоритма, кроме четвертого, осуществляется &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; раз, а количество операций на этапе 4 составляет (снова по порядку) &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;, то общее количество арифметических действий составляет &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Представим информационный граф алгоритма для этапов 1-4, поскольку этапы 5-7 реализуются аналогично этапам 1-3.&lt;br /&gt;
&lt;br /&gt;
[[File:pois3d_graph.png|center|thumb|600px|Зеленые прямоугольники обозначают одномерные сечения входного трехмерного массива. Красным кругом обозначена операция одномерного БПФ, например &amp;lt;math&amp;gt;FFT_{x11}&amp;lt;/math&amp;gt; означает БПФ вдоль оси x при &amp;lt;math&amp;gt;j=1,~k=1&amp;lt;/math&amp;gt;. Желтыми кругами представлены поэлементные преобразования массива для получения коэффициентов Фурье решения (этап 4 алгоритма), например &amp;lt;math&amp;gt;L_{2N,1,...,N}&amp;lt;/math&amp;gt; означает преобразование элементов &amp;lt;math&amp;gt;i=2,~j=N,~k=1,...,N&amp;lt;/math&amp;gt;. Для удобства целочисленные индексы нумеруются числами &amp;lt;math&amp;gt;1,...,N&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;0,...,N-1&amp;lt;/math&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Информационная зависимость между ярусами графа заключается в том, что одномерное БПФ зависит от результата произведенного ранее БПФ по перпендикулярному направлению (т.е. с предыдущего яруса), только если обрабатываемые этими БПФ одномерные сечения массива пересекаются. Следовательно, каждое из БПФ по второй координате, &amp;lt;math&amp;gt;FFT_{i,y,k},~i=1,...,N&amp;lt;/math&amp;gt;, зависит от результатов каждого из БПФ по первой координате &amp;lt;math&amp;gt;FFT_{x,j,k},~j=1,...,N&amp;lt;/math&amp;gt;, и только от них, если эти преобразования производятся в одной плоскости &amp;lt;math&amp;gt;k=K&amp;lt;/math&amp;gt;. Соответственно, каждое БПФ по третьей координате &amp;lt;math&amp;gt;FFT_{i,j,z},~j=1,...,N&amp;lt;/math&amp;gt;, зависит от каждого БПФ по второй координате &amp;lt;math&amp;gt;FFT_{i,y,k},~k=1,...,N&amp;lt;/math&amp;gt;, в одной плоскости &amp;lt;math&amp;gt;i=I&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном выше алгоритме можно выделить, по меньшей мере, два уровня параллелизма. Во-первых, вычисление каждого одномерного БПФ может быть распределено между вычислительными ядрами. И, во-вторых, на каждом этапе алгоритма (ярусе графа) одномерные БПФ независимы друг от друга и также могут быть выполнены паралельно (координатный параллелизм). Для сопоставления параллельной (при координатном распараллеливании) и последовательной сложности алгоритма определим в качестве основных операций одномерное БПФ и поэлементный перерасчет массива (этап 4 алгоритма). Тогда последовательный алгоритм будет состоять из последовательно выполняемых &amp;lt;math&amp;gt;6N^2&amp;lt;/math&amp;gt; одномерных БПФ и &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt; операций над отдельными элементами массива, параллельный же алгоритм будет выполнен за 6 шагов одномерного БПФ и 1 операцию поэлементного преобразования. Если же выразить введенные макрооперации через элементарные арифметические операции, то получим, что сложность последовательного алгоритма - &amp;lt;math&amp;gt;6N^3(\text{log}_2N)+N^3&amp;lt;/math&amp;gt;, а сложность параллельного - &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&amp;lt;/math&amp;gt;. Тогда при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; отношение последовательной сложности к параллельной становится равным &amp;lt;math&amp;gt;\propto N^2(6\text{log}_2N \text{ln}2+\text{ln}2+5)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
В качестве входных данных выступает трехмерный массив &amp;lt;math&amp;gt;N \times N \times N&amp;lt;/math&amp;gt; правой части уравнения. Выходной массив - трехмерный массив решения той же размерности.&lt;br /&gt;
&lt;br /&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;N^3&amp;lt;/math&amp;gt;, вычислительная мощность последовательного алгоритма становится равной &amp;lt;math&amp;gt;6\text{log}_2N+1&amp;lt;/math&amp;gt;, а параллельного алгоритма - &amp;lt;math&amp;gt;(6N\text{log}_2N+1)/N^3 \propto N^{-2}&amp;lt;/math&amp;gt; (при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Приведем пример реализации алгоритма на языке Фортран-90 с применением библиотеки  [http://www.fftw.org/ FFTW]. &lt;br /&gt;
В этом случае трехмерное прямое преобразование Фурье правой части уравнения реализуется как последовательность трех одномерных (этапы 1-3 в п.1.5). &lt;br /&gt;
Полученные коэффициенты Фурье делятся на собственное число оператора Лапласа (этап 4 в п.1.5) (см. комментарии в коде):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workfor_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_x,workfor_x,workfor_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workfor_x(1:i1)) )&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workfor_x(1:i1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_y,workfor_y,workfor_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workfor_y(1:j1)) )&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workfor_y(1:j1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! z - transform and dividing by eigenvalue&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_z,workfor_z,workfor_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workfor_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workfor_z(1:k1)) )&lt;br /&gt;
             ! Dividing by eigenvalue of Laplace operator&lt;br /&gt;
             sinx = sin((i-1) * Pi / i1)^2 * 4&lt;br /&gt;
             siny = sin((j-1) * Pi / j1)^2 * 4&lt;br /&gt;
             do k = 1, k1&lt;br /&gt;
               sinz = sin((k-1) * Pi / k1)^2 * 4&lt;br /&gt;
               f_r(i,j,1:k1) = f_r(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
               f_i(i,j,1:k1) = f_i(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
             enddo&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как только коэффициенты Фурье решения найдены, аналогично производится обратное преобразование Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! inverse x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workback_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_x,workback_x,workback_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workback_x(1:i1)) )/real(i1)&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workback_x(1:i1)) )/real(i1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_y,workback_y,workback_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workback_y(1:j1)) )/real(j1)&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workback_y(1:j1)) )/real(j1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse z - transform&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_z,workback_z,workback_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workback_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workback_z(1:k1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как видим, вложенность циклов соответствует порядку расположения элементов массивов в языке Фортран - по столбцам - это позволяет существенно сократить время обращения к памяти.&lt;br /&gt;
Многократно используются одни и те же вспомогательные массивы, что при небольших размерах сетки должно обеспечить быстроту работы с кэш-памятью. &lt;br /&gt;
Однако, данная реализация не является оптимальной. Так, вместо многократного вызова подпрограммы FFTW_EXECUTE_DFT в циклах, можно было бы обращаться к одной подпрограмме, выполняющей&lt;br /&gt;
заданное множество одномерных БПФ.&lt;br /&gt;
&lt;br /&gt;
Из приведенных выше листингов программы становится очевиден также и ресурс параллелизма алгоритма: каждое одномерное преобразование Фурье выполняется независимо. Самым простым способом использования этого обстоятельства будет вставка соответствующих директив OpenMP перед внутренними циклами - в случае использования многоядерной архтитектуры компьютера на общей памяти. В случае же параллельного выполнения на кластерах с распределенной памятью, необходимо будет позаботиться о распределении входного массива (правой части уравнения) между процессорами, а также &amp;quot;транспозиции&amp;quot; массивов при переходе от БПФ по одному из направлений к БПФ по следующему направлению.&lt;br /&gt;
&lt;br /&gt;
Заметим также, что в приведенной выше реализации для расчета одномерного БПФ производится вызов процедуры библиотеки FFTW, обрабатывающей массив комплексных чисел. В то же время, существует вариант БПФ для преобразования действительных массивов, ускоряющий БПФ в два раза (более подробно см. на [http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data сайте проекта FFTW]).&lt;br /&gt;
&lt;br /&gt;
Важным обстоятельством является то, что большинство вариантов БПФ, включая алгоритм Кули-Тьюки, в арифметике с плавающей запятой имеют очень низкую погрешность.  Верхняя граница относительной ошибки для алгоритма Кули-Тьюки составляет &amp;lt;math&amp;gt;O(\epsilon \log N)&amp;lt;/math&amp;gt; (для сравнения - относительная ошибка преобразования Фурье непосредственно по формуле дискретного преобразования Фурье - &amp;lt;math&amp;gt;O(\epsilon  N^{3/2})&amp;lt;/math&amp;gt;) &amp;lt;ref&amp;gt; Gentleman, W. M.; Sande, G. (1966). &amp;quot;Fast Fourier transforms—for fun and profit&amp;quot;. Proc. AFIPS 29: 563–578. doi:10.1145/1464291.1464352 &amp;lt;/ref&amp;gt;. Поэтому для ускорения алгоритма можно использовать одинарную точность представления переменных без существенного увеличения ошибки.&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
Как было показано выше, существует, по меньшей мере, два уровня параллелизма в описываемом алгоритме. Во-первых, это параллельная реализация одномерных БПФ и, во-вторых, координатный параллелизм - параллельное исполнение независимых одномерных БПФ &amp;lt;ref&amp;gt;Anshu Dubey and Daniele Tessera. Redistribution strategies for portable parallel FFT: a case study. Concurrency and Computation: Practice and Experience, 13(3):209–220, 2001.&amp;lt;/ref&amp;gt;. Эти два уровня могут быть скомбинированы, например, путем распределения разных БПФ между MPI-процессами, а каждого отдельного БПФ - между нитями на общей памяти (POSIX, OpenMP, и т.д.). Ниже мы приведем детали базового алгоритма распараллеливания с использованием координатного параллелизма, рассмотрим его недостатки и перечислим возможные способы повышения его масштабируемости.&lt;br /&gt;
&lt;br /&gt;
Координатный параллелизм в контексте данной задачи реализуется в результате разбиения трехмерной области на подобласти, в каждой из которых можно независимо от расчетов в других подобластях, выполнить одномерные БПФ. К настоящему времени предложены две реализации такого подхода: одномерное разбиение области (slab decomposition) и двумерное разбиение (pencil decomposition) &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;. При одномерном разбиении требуется меньшее количество MPI-пересылок, однако, максимальное количество процессоров/ядер ограничено максимальным по трем измерениям размером области. Поэтому с точки зрения массивного параллелизма двумерная декомпозиция предпочтительнее, и ниже мы остановимся на этом подходе.&lt;br /&gt;
&lt;br /&gt;
При MPI-реализации необходимо принять во внимание накладные расходы, вызванные пересылками данных между процессорами. Для реализации обсуждаемого алгоритма необходимо осуществлять т.н. транспонирования массивов, при которых на каждом из трех этапов преобразования Фурье (этапы 1-3 и 5-7 в п.1.5) обеспечивается нахождение элементов массива вдоль соответствующих направлений в памяти соответствующих процессоров:&lt;br /&gt;
&lt;br /&gt;
[[File:transp.png|center|thumb|800px|Транспонирование трехмерного массива при параллельной реализации трехмерного БПФ]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим соотношение вычислений и пересылок данных при MPI-реализации. Вычислительная сложность алгоритма при покоординатном распараллеливании, при запуске на &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; MPI-процессах составляет  &amp;lt;math&amp;gt; \left(6N^3(\log_2 N) + N^3\right)/M&amp;lt;/math&amp;gt;, т.е., в лучшем случае, &amp;lt;math&amp;gt; 6N(\log_2 N) + N&amp;lt;/math&amp;gt; (на &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; процессах). При этом, суммарное количество отсылаемых и получаемых MPI-пакетов составляет &amp;lt;math&amp;gt;8N_{px}+4N_{py}&amp;lt;/math&amp;gt;, а суммарное количество отсылаемых и получаемых элементов массива на каждом процессе - &amp;lt;math&amp;gt;12N^3/(N_{px}N_{py})&amp;lt;/math&amp;gt; (здесь - &amp;lt;math&amp;gt;N_{px},~N_{py}&amp;lt;/math&amp;gt; - количества процессов в двумерной MPI-декомпозиции области по осям &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;, соответственно - см. рис. выше). Учитывая, что &amp;lt;math&amp;gt;M=N_{px}N_{py}&amp;lt;/math&amp;gt;, получаем, что отношение количества пересылаемых элементов массива к количеству арифметических операций составляет &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N + 1)&amp;lt;/math&amp;gt;. Таким образом, отношение объема пересылаемых элементов к количеству операций не зависит от количества MPI-процессов и уменьшается с ростом размера задачи. При больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, однако, эта зависимость становится слабой, т.е. &amp;quot;насыщается&amp;quot;. В то же время, при фиксированном размере задачи, рост количества используемых процессов, не изменяя параметра &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;, вызывает рост числа пакетов (&amp;lt;math&amp;gt;\propto \sqrt{M}&amp;lt;/math&amp;gt;, в силу &amp;lt;math&amp;gt;N_{px} \propto N_{py} \propto \sqrt{M}&amp;lt;/math&amp;gt; и формул, приведенных выше). В силу латентности сети, это приводит к росту времени пересылки единицы данных и, следовательно, замедлению ускорения алгоритма. &lt;br /&gt;
&lt;br /&gt;
Приведенный здесь анализ может служить только для ориентировочных оценок, поскольку он не дает времен вычислений и MPI-обменов. Более детальные расчеты для случаев одномерной и двумерной декомпозиции области обширно представлены в литературе &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;P. Dmitruk, L.-P. Wang, W.H. Matthaeus, R. Zhang, D. Seckel, Scalable parallel FFT for spectral simulations on a Beowulf cluster, Parallel Comput. 27&lt;br /&gt;
(2001) 1921–1936.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В профилируемом в следующих разделах программном коде параллельной реализации алгоритма вызовы одномерных БПФ по трем направлениям, показанные в листинге п.2.1, перемежаются вызовами специальных процедур, осуществляющих транспонирование массива. Отдельно транспонируются действительная и мнимая части массива (что уже не оптимально - лучше пересылать комплексные числа) с помощью коммуникаций &amp;quot;точка-точка&amp;quot;. При этом используются асинхронные пересылки с помощью MPI_ISEND и MPI_IRECV.&lt;br /&gt;
&lt;br /&gt;
=== Результаты прогонов ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D0%B0%D0%B1%D0%B8%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%B1%D0%B8%D1%81%D0%BE%D0%BF%D1%80%D1%8F%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_(BiCGStab)&amp;diff=29723</id>
		<title>Стабилизированный метод бисопряженных градиентов (BiCGStab)</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D0%B0%D0%B1%D0%B8%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%B1%D0%B8%D1%81%D0%BE%D0%BF%D1%80%D1%8F%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_(BiCGStab)&amp;diff=29723"/>
		<updated>2025-02-20T11:19:59Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы описания:&lt;br /&gt;
[https://algowiki-project.org/ru/Участник:Novikov_alexander&amp;lt;b&amp;gt;А.Новиков&amp;lt;/b&amp;gt;] (разделы 1.4, 1.6, 1.7, 3),&lt;br /&gt;
[https://algowiki-project.org/ru/Участник:EasyBreezy&amp;lt;b&amp;gt;А.Гаврилов&amp;lt;/b&amp;gt;] (разделы 1.1-1.3, 1.5, 1.8, 1.9, 3)&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = BiCGStab&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt; O(I \cdot N^2) &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt; - размерность СЛАУ, &amp;lt;math&amp;gt;I&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt; O(k\cdot(6 \sqrt N + 4N + 5 \lceil \frac{N}{p} \rceil)) &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt; 2 \sqrt N &amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;N^2+N&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;N&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;
Стабилизированный метод бисопряженных градиентов, так же известный как BiCGStab (BiConjugate Gradient Stabilized method), был предложен голландским математиком Хенком ван дер Ворстом&amp;lt;ref&amp;gt;Henk A. vander Vorst, Iterative Krylov Methods for Large Linear Systems, Cambridge University Press 2003, 230p&amp;lt;/ref&amp;gt; в 1992 году. Статья, в которой описывался метод, стала самым цитируемым научным трудом в области математики в 1990х годах.&lt;br /&gt;
&lt;br /&gt;
Метод появился, как ответ на задачу о построении способа решения систем линейных алгебраических уравнений произвольного вида. На момент появления BiCGStab уже существовали методы решения СЛАУ произвольного типа, в том числе и в комплексном пространстве, например метод бисопряженных градиентов. Однако существующие на тот момент методы либо обладали недостаточной скоростью сходимости, либо использовали в вычислениях тяжелые операции, такие как транспонирования матрицы, которые усложняли распараллеливание на многопроцессорных машинах.&lt;br /&gt;
&lt;br /&gt;
BiCGStab является итерационным методом решения систем линейных алгебраических уравнений. Мощь метода заключается в том, что его можно применять к матрицам общего вида, в том числе с комплексными коэффициентами. В процессе выполнения BiCGStab не использует для вычисления плохо распараллеливаемых операций, не допускает накопления погрешностей округления и нестабильного поведения невязки. Эти факторы выгодно отличают его от предшественников: метода бисопряженных градиентов и квадратичного метода сопряженных градиентов, из которого BiCGStab фактически и вытекает. К преимуществам так же можно добавить более высокую в общем случае скорость сходимости относительно ближайших конкурентов. Тем не менее, для некоторых видов СЛАУ BiCGStab может уступать более простым методам.&amp;lt;ref&amp;gt;Горбаченко В.И, Вычислительная линейная алгебра с примерами на MATLAB. — СПб.: БХВ-Петербург, 2011. — 320 с.: ил. — (Учебное пособие)&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Благодаря свойствам алгоритма область применения метода весьма широка. Фактически, он используется во всех задачах, где требуется решать СЛАУ, в том числе СЛАУ большой размерности, к которым сводится большое количество численных методов, применяемых при решении задач математического моделирования. &lt;br /&gt;
&lt;br /&gt;
BiCGStab относится к классу так называемых проекционных методов. Основная идея методов данного класса: искать итерационным способом наилучшее приближение решения в некотором подпространстве пространства &amp;lt;math&amp;gt;R^n&amp;lt;/math&amp;gt;, и чем шире подпространство, в котором ищется приближение решения, тем ближе будет приближенное решение к точному на каждой итерации. В качестве такого подпространства используются пространства Крылова, порожденные матрицей системы и невязкой первого приближения: &amp;lt;math&amp;gt;K^m (A, r^0) = \rm span(r^0, Ar^0, A^2r^0, ..., A^{m-1} r^0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Изложим основную идею любого проекционного метода, заложенную в том числе и в BiCGStab. Для простоты выкладок и рассуждений здесь и далее будем считать, что матрица системы и ее правая часть вещественны. Без ограничения общности все дальнейшие рассуждения могут быть перенесены и на комплексный случай. Итак, пусть решается система &amp;lt;math&amp;gt;Ax=b&amp;lt;/math&amp;gt; с невырожденной матрицей  &amp;lt;math&amp;gt;A \in R^{n \times n}&amp;lt;/math&amp;gt; и ненулевым  вектором  &amp;lt;math&amp;gt;b \in R^n&amp;lt;/math&amp;gt;.  Имеются  два подпространства &amp;lt;math&amp;gt;K_n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;L_n&amp;lt;/math&amp;gt;. Требуется найти вектор &amp;lt;math&amp;gt;x \in K_n&amp;lt;/math&amp;gt;, который обеспечивает решение  системы, оптимальное относительно подпространства  &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt;, то есть требуется выполнение условия Петрова-Галеркина: &amp;lt;math&amp;gt;(Ax,z)=(b,z), \forall z \in L_n&amp;lt;/math&amp;gt;. В данном случае вектор x называется обобщенным решением системы. &lt;br /&gt;
&lt;br /&gt;
Условие Петрова-Галеркина можно записать и через определение невязки. Пусть &amp;lt;math&amp;gt;r = b - Ax&amp;lt;/math&amp;gt; - невязка, тогда условие Петрова-Галеркина перепишется в виде: &amp;lt;math&amp;gt;(b - Ax, z)=(r, z),\forall z \in L_n&amp;lt;/math&amp;gt;. Это равносильно тому, что вектор невязки ортогонален пространству &amp;lt;math&amp;gt;L_n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть для СЛАУ известно некоторое приближение &amp;lt;math&amp;gt;x^0&amp;lt;/math&amp;gt; точного решения &amp;lt;math&amp;gt;x^*&amp;lt;/math&amp;gt;. Данное приближение требуется уточнить поправкой &amp;lt;math&amp;gt; \delta: b - Ax^0 + \delta \perp L&amp;lt;/math&amp;gt;. Невязка уточненного решения имеет вид: &amp;lt;math&amp;gt;r_{new} = b - Ax^0 + \delta = r^0- A\delta&amp;lt;/math&amp;gt;. Условие Петрова-Галеркина тогда можно переписать так: &amp;lt;math&amp;gt;(r_{new}, z)= r^0 - (A\delta, z) = 0, \forall z \in L&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть  &amp;lt;math&amp;gt;\rm dim K = dim L = m, V = (v_1, ..., v_n) \in R^{n \times m}, W = (w_1, ... w_n) \in R^{n \times m}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; – матрицы, столбцы которых образуют базисы пространств &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; соответственно. Пусть так же &amp;lt;math&amp;gt; \delta = Vy, z = Wq&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; – коэффициенты разложения вектора поправки по базису пространства &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;q&amp;lt;/math&amp;gt; – коэффициенты разложения вектора &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; в пространстве &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt;. Тогда новое приближение решения можно записать в виде: &amp;lt;math&amp;gt;x^1 = x^0 + \delta= x^0 + Vy&amp;lt;/math&amp;gt;. Из условия ортогональности Петрова-Галеркина получаем, что: &amp;lt;math&amp;gt;(r - AVy, Wq) = (W^Tr^0 - AVy, q) = 0&amp;lt;/math&amp;gt;. Поскольку &amp;lt;math&amp;gt;q \neq 0&amp;lt;/math&amp;gt;, то получаем СЛАУ для вектора &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;W^TAVy = W^Tr^0&amp;lt;/math&amp;gt;. Если предположить, что матрица &amp;lt;math&amp;gt;W^TAVy&amp;lt;/math&amp;gt; невырождена, то вектор y однозначно определяется и равен: &amp;lt;math&amp;gt;y = W^TAV^{-1}W^Tr^0&amp;lt;/math&amp;gt;. Подставляя найденные коэффициенты разложения в выражение для первого приближения получаем: &amp;lt;math&amp;gt;x^1 = x^0 + \delta = x^0 + W^TAV^{-1}W^Tr^0y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Подведем итог. Общий порядок шагов любого проекционного метода следующий:&lt;br /&gt;
#Выбрать пару подпространств &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt;&lt;br /&gt;
#Найти базис V пространства K и базис W пространства &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt;;&lt;br /&gt;
#Вычислить невязку&lt;br /&gt;
#Найти &amp;lt;math&amp;gt;y = W^T AV^{-1} W^T r^0&amp;lt;/math&amp;gt;&lt;br /&gt;
#Положить &amp;lt;math&amp;gt;x = x + Vy&amp;lt;/math&amp;gt;&lt;br /&gt;
#Если не достигнут критерий остановки итерационного процесса, то повторить алгоритм, начиная с первого шага.&lt;br /&gt;
&lt;br /&gt;
Как будет показано далее, в BiCGStab не требуется вычислять матрицу &amp;lt;math&amp;gt;W^T AV^{-1}&amp;lt;/math&amp;gt; в явном виде.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим СЛАУ с вещественными коэффициентами:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;Ax = b, \quad A \in R^{N \times N}, \quad b \in R^N.&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В основу алгоритма ложиться идея проекционного метода и использование свойства A-бисопряженности системы векторов, а именно: векторы &amp;lt;math&amp;gt;p^1, p^2, ...&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\overline p^1, \overline p^2, ...&amp;lt;/math&amp;gt; бисопряжены, если &amp;lt;math&amp;gt;(Ap^i,p^j ) = 0&amp;lt;/math&amp;gt;, при &amp;lt;math&amp;gt;i \neq j&amp;lt;/math&amp;gt;. Фактически, данное условие эквивалентно биортогональности относительно энергетического скалярного произведения. &lt;br /&gt;
 &lt;br /&gt;
Общая концепция проекционных методов предписывает нам выбрать два подпространства. В нашем случае подпространства мы выберем два подпространства, задаваемые матрицей системы А, вектором невязки на нулевой итерации &amp;lt;math&amp;gt;r^0&amp;lt;/math&amp;gt; и вектором &amp;lt;math&amp;gt;\overline r^0&amp;lt;/math&amp;gt;. который выбирается из условия &amp;lt;math&amp;gt;(r^0, \overline r^0) \neq 0&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;K = K^k(A, r^0),\quad L = K^k(A, \overline r^0).&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
Метод основан на построении биортогонального базиса &amp;lt;math&amp;gt;p^0, p^1, ..., p^k, ... &amp;lt;/math&amp;gt; пространства &amp;lt;math&amp;gt;K^k (A, r^0) &amp;lt;/math&amp;gt; и вычислении поправки такой, что новое приближение на очередной итерации было бы ортогонально второму подпространству Крылова. Базисные вектора строятся до тех пор, пока не будет достигнут критерий остановки итерационного процесса, а каждое последующее приближение формируется, как сумма приближения на предыдущей итерации и найденной поправки. Критерием останова итерационного процесса является достижение невязкой значения, которое меньше некоторого наперед заданного &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Основной итерационный процесс задается формулами:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;x^{k + 1} = x^k + \alpha_k p_k + \omega_k s_k&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;p^{k + 1} = r^{k + 1} + \beta_k p_k - \omega_k Ap_k&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
#&amp;lt;math&amp;gt;x^{k + 1}&amp;lt;/math&amp;gt; - приближение на следующей итерации&lt;br /&gt;
#&amp;lt;math&amp;gt;x^k&amp;lt;/math&amp;gt; - приближение на предыдущей итерации&lt;br /&gt;
#&amp;lt;math&amp;gt;p_k&amp;lt;/math&amp;gt; - базисный вектор подпространства Крылова, порожденного матрице СЛАУ и невязкой&lt;br /&gt;
#&amp;lt;math&amp;gt;\alpha_k, \omega_k&amp;lt;/math&amp;gt; - вспомогательные скаляры, определяемые для каждого шага итерации&lt;br /&gt;
#&amp;lt;math&amp;gt;s_k&amp;lt;/math&amp;gt; - вспомогательный вектор&lt;br /&gt;
#&amp;lt;math&amp;gt;p^{k + 1}&amp;lt;/math&amp;gt; - &amp;lt;math&amp;gt;k + 1&amp;lt;/math&amp;gt;-ый базисный вектор&lt;br /&gt;
#&amp;lt;math&amp;gt;r^{k + 1}&amp;lt;/math&amp;gt; - невязка &amp;lt;math&amp;gt;k + 1&amp;lt;/math&amp;gt;-ой итерации&lt;br /&gt;
#&amp;lt;math&amp;gt;\beta_k&amp;lt;/math&amp;gt; - вспомогательный коэффициент&lt;br /&gt;
&lt;br /&gt;
Вспомогательный вектор выражается следующим образом:&lt;br /&gt;
*&amp;lt;math&amp;gt;s_k = r^k - \alpha_k Ap_k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вспомогательные коэффициенты вычисляются по формулам:&lt;br /&gt;
*&amp;lt;math&amp;gt;\alpha_k = \frac{(r^k, \overline r^0)}{(Ap_k, \overline r^0)}&amp;lt;/math&amp;gt;&lt;br /&gt;
*&amp;lt;math&amp;gt;\omega_k = \frac{(As_k, s_k)}{(As_k, As_k)}&amp;lt;/math&amp;gt;&lt;br /&gt;
*&amp;lt;math&amp;gt;\beta_k = \frac{(r^{k + 1}, \overline r^0)}{(r^k, \overline r^0)}&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;x^0&amp;lt;/math&amp;gt;&lt;br /&gt;
#По выбранному приближению находится невязка &amp;lt;math&amp;gt;r^0 = b - Ax^0&amp;lt;/math&amp;gt;&lt;br /&gt;
#Из условия &amp;lt;math&amp;gt;(r^0, \overline r^0) \neq 0&amp;lt;/math&amp;gt; выбирается вектор &amp;lt;math&amp;gt;\overline r^0&amp;lt;/math&amp;gt;&lt;br /&gt;
#Положим &amp;lt;math&amp;gt;p^0 = r^0&amp;lt;/math&amp;gt;&lt;br /&gt;
#Устанавливаем счетчик итераций: &amp;lt;math&amp;gt;n = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:Итерационный процесс:&lt;br /&gt;
#Находим &amp;lt;math&amp;gt;\alpha_k&amp;lt;/math&amp;gt;&lt;br /&gt;
#По найденному &amp;lt;math&amp;gt;\alpha_k&amp;lt;/math&amp;gt; вычисляем &amp;lt;math&amp;gt;s_k&amp;lt;/math&amp;gt;&lt;br /&gt;
#По найденному &amp;lt;math&amp;gt;s_k&amp;lt;/math&amp;gt; вычисляется вспомогательный коэффициент &amp;lt;math&amp;gt;\omega_k&amp;lt;/math&amp;gt;&lt;br /&gt;
#Находится новое приближение &amp;lt;math&amp;gt;x^{k + 1}&amp;lt;/math&amp;gt;&lt;br /&gt;
#Вычисляется невязка &amp;lt;math&amp;gt;r^{k + 1}&amp;lt;/math&amp;gt;. Если выполнено условие &amp;lt;math&amp;gt;\parallel r^{k + 1} \parallel &amp;lt; \epsilon&amp;lt;/math&amp;gt;, то алгоритм завершается.&lt;br /&gt;
#Вычисляется вспомогательный коэффициент &amp;lt;math&amp;gt;\beta_k&amp;lt;/math&amp;gt;&lt;br /&gt;
#Вычисляется новый базисный вектор: &amp;lt;math&amp;gt;p^{k + 1}&amp;lt;/math&amp;gt;&lt;br /&gt;
#Увеличивается номер итерации: &amp;lt;math&amp;gt;n = n + 1&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;
# [[Скалярное произведение векторов, вещественная версия, последовательно-параллельный вариант]] x 4 раза&lt;br /&gt;
# [[Умножение плотной матрицы на вектор ]] х 2 раза&lt;br /&gt;
&lt;br /&gt;
===Схема реализации последовательного алгоритма===&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Всего в вычислительном блоке алгоритма присутствует 20 трудоемких операций: 2 операции умножения матрицы на вектор, 6 скалярных произведений и 6 сложений/вычитаний векторов и 6 умножений вектора на число.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&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;2N - 1&amp;lt;/math&amp;gt; операции. Скалярных произведений всего 6 штук (включая поиск нормы), что дает нам &amp;lt;math&amp;gt;12N - 6&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Умножение матрицы размерности &amp;lt;math&amp;gt;N \times N&amp;lt;/math&amp;gt; на вектор эквивалентно взятию еще &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; скаляров, и так как таких операций в вычислительном ядре 2, то дополнительно имеется еще &amp;lt;math&amp;gt;2N(2N - 1)&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Наконец, сложение или вычитание векторов требует &amp;lt;math&amp;gt;6N&amp;lt;/math&amp;gt; соотвествующих операций. Столько же требует 6 произведений вектора на число.&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;2N(2N - 1) + 12N - 6 + 6N + 6N = 4N^2 + 22N - 6&amp;lt;/math&amp;gt; операций за одну итерацию. Домножая это на количество итераций &amp;lt;math&amp;gt;I&amp;lt;/math&amp;gt;, получаем итоговую сложность алгоритма: &amp;lt;math&amp;gt;I \cdot (4N^2 + 22N - 6)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Имеются так же операции как, извлечение квадратного корня и деление вещественных чисел друг на друга, но они не принимаются в расчет, так как они не влияют на итоговый результат. Окончательно можно заключить, что последовательная сложность алгоритма эквивалента &amp;lt;math&amp;gt;O(I \cdot N^2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[file:BiCGStabIterations.jpg|thumb|center|800px|&amp;lt;center&amp;gt;Информационный граф.&amp;lt;/center&amp;gt;]]&lt;br /&gt;
На графе представлены связи между операциями, выполняющимися в первых трех итерациях метода. При выполнении большего, чем 3, количества итераций, структура каждой новой будет повторять структуру третьей. Связи между итерациями не представлены, т.к. они не важны для понимания параллельной структуры алгоритма. Серым обозначено перемножение чисел, красным - умножение числа на вектор&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Основной прирост производительности параллельной версии алгоритма дает использование параллельных операций вычисления скалярного произведения, суммы векторов, а так же произведения матрицы на вектор. Каждая из операций вычисления скалярного произведения и суммы векторов, выполняемая на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; процессорах, за счет метода сдваивания может ускориться до &amp;lt;math&amp;gt; \frac{p}{\log_2 p} &amp;lt;/math&amp;gt; раз. Ускорение же умножения матрицы на вектор может достигать &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
Ширина и высота ЯПФ графа данного алгоритма напрямую зависит от конкретных реализаций макроопераций и входных данных.&lt;br /&gt;
&lt;br /&gt;
Для последовательно-параллельной реализации операции взятия скалярного произведения в наиболее оптимальном случае (&amp;lt;math&amp;gt;p= \sqrt N&amp;lt;/math&amp;gt;) высота будет равна &amp;lt;math&amp;gt;2 \sqrt N - 1&amp;lt;/math&amp;gt;, а ширина &amp;lt;math&amp;gt;\sqrt 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&amp;lt;/math&amp;gt;, а ширина &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - это уже упомянутая длина вектора(она же ширина матрицы), а m - высота матрицы.&lt;br /&gt;
&lt;br /&gt;
Высота ЯПФ операции умножения вектора на число равна &amp;lt;math&amp;gt;\frac{N}{p}&amp;lt;/math&amp;gt;, а ширина &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Высота ЯПФ операции вычисления разности векторов равна &amp;lt;math&amp;gt; \log_2 p &amp;lt;/math&amp;gt;, а ширина &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В конечном счете общую высоту ЯПФ одной итерации алгоритма можно оценить, как &amp;lt;math&amp;gt;6 \sqrt N-3 + 4N + 3 + 1 + 3\lceil \frac{N}{p} \rceil + 2 \lceil \frac{N}{p} \rceil = 4N + 6 \sqrt N + 5 \lceil \frac{N}{p} \rceil + 1&amp;lt;/math&amp;gt;, а ширину, как &amp;lt;math&amp;gt;2 \sqrt N&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;A \in R^{N \times N}&amp;lt;/math&amp;gt; ( &amp;lt;math&amp;gt;C^{N \times N}&amp;lt;/math&amp;gt; )&lt;br /&gt;
#Вектор правой части &amp;lt;math&amp;gt;b \in R^N&amp;lt;/math&amp;gt; ( &amp;lt;math&amp;gt;C^N&amp;lt;/math&amp;gt; )&lt;br /&gt;
&lt;br /&gt;
:Выходные данные:&lt;br /&gt;
#Вектор решения СЛАУ &amp;lt;math&amp;gt;x \in R^N&amp;lt;/math&amp;gt; ( &amp;lt;math&amp;gt;C^N&amp;lt;/math&amp;gt; )&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
BiCGStab хорошо зарекомендовал себя для решения систем линейных алгебраический уравнений, поскольку обладает некоторыми важными свойствами:&lt;br /&gt;
#Благодаря применению подхода Петрова-Галеркина и техники ортогонализации, он численно устойчив&lt;br /&gt;
#Не меняется вид матрицы в процессе решения&lt;br /&gt;
#Эффективен для решения систем большой размерности с разреженной матрицей, поскольку в методе самая трудоемкая операция - умножение матрицы на вектор&lt;br /&gt;
#Лучше подходит под распределенные системы, поскольку не содержит операции транспонирования матрицы&lt;br /&gt;
#Применим для решения систем с несимметричными матрицами&lt;br /&gt;
#Вычислительная мощность: &amp;lt;math&amp;gt;N/4&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;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[en:Biconjugate gradient stabilized method (BiCGStab)]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=29722</id>
		<title>Последовательно-параллельный метод суммирования</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=29722"/>
		<updated>2025-02-20T10:13:29Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Последовательно-параллельный метод суммирования&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(\sqrt{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(\sqrt{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Последовательно-параллельный метод&#039;&#039;&#039; используется в качестве эрзаца блочной реализации вычисления длинных последовательностей ассоциативных операций (например, массового суммирования). Получил распространение благодаря следующим особенностям: а) реализует приём получения двойных циклов из одинарных; б) в последовательной архитектуре компьютеров позволял для ряда операций уменьшать влияние округления на результат. Здесь будем описывать его версию для суммирования чисел.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; чисел.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: сумма элементов массива.&lt;br /&gt;
&lt;br /&gt;
Формулы метода: число &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; разлагается в выражение типа &amp;lt;math&amp;gt;N = (p - 1) k + q&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — количество процессоров, &amp;lt;math&amp;gt;k = \lceil \frac{N}{p} \rceil&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;q = N - k (p - 1)&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;i &amp;lt; p&amp;lt;/math&amp;gt;) последовательно вычисляется сумма элементов массива, начиная с &amp;lt;math&amp;gt;(i - 1) k + 1&amp;lt;/math&amp;gt;-го, до &amp;lt;math&amp;gt;i k&amp;lt;/math&amp;gt;-го.&lt;br /&gt;
:&amp;lt;math&amp;gt;S_i = \sum_{j = 1}^k x_{k (i - 1) + j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;-м процессоре последовательно вычисляется сумма элементов массива, начиная с &amp;lt;math&amp;gt;(p - 1) k + 1&amp;lt;/math&amp;gt;-го до &amp;lt;math&amp;gt;(p - 1) k + q&amp;lt;/math&amp;gt;-го.&lt;br /&gt;
:&amp;lt;math&amp;gt;S_p = \sum_{j = 1}^q x_{k (p - 1) + j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
По окончании этого процесса процессоры обмениваются данными и на одном из них (либо на всех одновременно, если результат нужен далее на всех процессорах) получившиеся суммы суммируются последовательно друг с другом.&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{i = 1}^p S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро последовательно-параллельного метода суммирования можно составить из множественных (всего &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;) вычислений сумм элементов массива:&lt;br /&gt;
:&amp;lt;math&amp;gt;S_i = \sum_{j = 1}^k x_{k (i - 1) + j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и ещё одного вычисления суммы элементов частичных сумм&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{i = 1}^p S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как уже записано в описании ядра алгоритма, основную часть метода составляют множественные (всего &amp;lt;math&amp;gt;p + 1&amp;lt;/math&amp;gt;) вычисления сумм&lt;br /&gt;
:&amp;lt;math&amp;gt;S_i = \sum_{j = 1}^k x_{k (i - 1) + j}&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{i = 1}^p S_i&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;
Для вычисления суммы массива, состоящего из &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;N - 1&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф алгоритма. В данном случае выполнено суммирование 24 элементов массива.&lt;br /&gt;
&lt;br /&gt;
[[file:series-parallel summation graph.png|center|thumb|600px|Рисунок 1. Последовательно-параллельный метод суммирования массива]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{{#widget:Algoviewer&lt;br /&gt;
|url=seq_par/Algo_view_seq_par4.html&lt;br /&gt;
|width=1300&lt;br /&gt;
|height=800&lt;br /&gt;
|border=1&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Интерактивное изображение графа алгоритма без входных и выходных данных для случая суммирования 20 элементов массива&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для суммирования массива порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; последовательно-параллельным методом в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
* &amp;lt;math&amp;gt;k - 1&amp;lt;/math&amp;gt; ярусов суммирования по частям массива (&amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; ветвей),&lt;br /&gt;
* &amp;lt;math&amp;gt;p - 1&amp;lt;/math&amp;gt; ярусов суммирования (одна последовательная ветвь).&lt;br /&gt;
 &lt;br /&gt;
Таким образом, в параллельном варианте критический путь алгоритма (и соответствующая ему высота ЯПФ) будет зависеть от произведённого разбиения массива на части. В оптимальном случае (&amp;lt;math&amp;gt;p = \sqrt{n}&amp;lt;/math&amp;gt;)  высота ЯПФ будет равна &amp;lt;math&amp;gt;2 \sqrt{n} - 2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, последовательно-параллельный метод относится к алгоритмам со сложностью &#039;&#039;корень квадратный&#039;&#039;. При классификации по ширине ЯПФ его сложность будет такой же — &#039;&#039;корень квадратный&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;\vec{x}&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;N&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;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;корнем квадратным&#039;&#039; (отношение линейной к корню квадратному). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных столько же, сколько операций)&#039;&#039;. При этом алгоритм не вполне полностью детерминирован, суммирование может быть проведено в разном порядке. Использование другого порядка выполнения ассоциативных операций может дать, с учётом особенностей входных данных, уменьшение влияния ошибок округления на результат. Дуги информационного графа локальны.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В простейшем (без перестановок суммирования) варианте на Фортране можно записать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	DO  I = 1, P&lt;br /&gt;
		S (I) = X(K*(I-1)+1)&lt;br /&gt;
		IF (I.LQ.P) THEN&lt;br /&gt;
			DO J = 2,K&lt;br /&gt;
				S(I)=S(I)+X(K*(I-1)+J)&lt;br /&gt;
		             END DO&lt;br /&gt;
		ELSE&lt;br /&gt;
			DO J = 2,Q&lt;br /&gt;
				S(I)=S(I)+X(K*(I-1)+J)&lt;br /&gt;
		             END DO&lt;br /&gt;
		END IF&lt;br /&gt;
	END DO&lt;br /&gt;
	SUM = S(1)&lt;br /&gt;
	DO I = 2, P&lt;br /&gt;
		SUM = SUM + S(I)&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно записать и аналогичные схемы, где суммирование будет проводиться в обратном порядке. Подчеркнём, что граф алгоритма обеих схем — [[#Информационный граф|один и тот же]]!&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В чистом виде алгоритм последовательно-параллельного метода для суммирования массива встречается редко, в основном встречаются его модификации, например для случаев вычисления скалярного произведения (вместо элементов массива будут фигурировать произведения элементов двух массивов), равномерной нормы (вместо элементов массива — их модули) и т. п. В случае вычисления скалярного произведения в одном из частных случаев подобный приём применён в библиотеке BLAS (там одна из размерностей равна 5), но, видимо, не для распараллеливания, а для оптимизации работы с регистрами процессора. Между тем, разбиения массивов на группы для вычислений частных сумм могут быть полезны и для лучшего использования кэша на отдельных узлах.&lt;br /&gt;
&lt;br /&gt;
=== Результаты прогонов ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
[[Категория:Последовательно-параллельная группировка операций]]&lt;br /&gt;
[[Категория:Векторные операции]]&lt;br /&gt;
&lt;br /&gt;
[[En:The serial-parallel summation method]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D0%BA%D0%B0%D0%BB%D1%8F%D1%80%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29721</id>
		<title>Скалярное произведение векторов, вещественная версия, последовательно-параллельный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D0%BA%D0%B0%D0%BB%D1%8F%D1%80%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29721"/>
		<updated>2025-02-20T10:09:48Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Скалярное произведение векторов, вещественная версия, последовательно-параллельный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(\sqrt{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(\sqrt{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Скалярное произведение векторов&#039;&#039;&#039; используется в качестве одной из базовых операций в широком круге методов. При этом используется как в версии скалярного произведения собственно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;-мерных векторов (одномерных массивов размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;), так и в версии скалярного произведения строк, столбцов и других линейных подмножеств массивов большей размерности. Последняя отличается от первой тем, что соответствующая подпрограмма получает, кроме стартовых адресов векторов, также и параметры смещения следующих элементов относительно предыдущих (в первой версии эти смещения равны 1). Разные формулы существуют для скалярных произведений в вещественной арифметике и для комплексных векторов. Здесь мы рассматриваем только вещественную арифметику и последовательно-параллельную реализацию.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: два одномерных массива n чисел.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: сумма попарных произведений элементов массива.&lt;br /&gt;
&lt;br /&gt;
Формулы метода: &lt;br /&gt;
число &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; разлагается в выражение типа &lt;br /&gt;
&amp;lt;math&amp;gt;n = (p - 1) k + q&amp;lt;/math&amp;gt;, &lt;br /&gt;
где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — количество процессоров, &amp;lt;math&amp;gt;k = \lceil \frac{n}{p} \rceil&amp;lt;/math&amp;gt;,&lt;br /&gt;
&amp;lt;math&amp;gt;q = n - k (p - 1)&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 &amp;lt; p&amp;lt;/math&amp;gt;) последовательно вычисляется «частичное» скалярное произведение подмассивов, начиная с &amp;lt;math&amp;gt;(i - 1) k + 1&amp;lt;/math&amp;gt;-го номера элемента, до &amp;lt;math&amp;gt;ik&amp;lt;/math&amp;gt;-го номера.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;S_i = \sum_{j = 1}^k a_{k (i - 1) + j} b_{k (i - 1) + j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;-м процессоре последовательно вычисляется «частичное» скалярное произведение подмассивов, начиная с &amp;lt;math&amp;gt;(p - 1) k + 1&amp;lt;/math&amp;gt;-го номера элемента до &amp;lt;math&amp;gt;(p - 1) k + q&amp;lt;/math&amp;gt;-го номера.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;S_p = \sum_{j = 1}^q a_{k (p - 1) + j} b_{k (p - 1) + j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
По окончании этого процесса процессоры обмениваются данными и на одном из них (либо на всех одновременно, если результат нужен далее на всех процессорах) получившиеся суммы суммируются последовательно друг с другом.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{i = 1}^p S_i&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;p&amp;lt;/math&amp;gt; вычислений «частных» скалярных произведений c последующим последовательным суммированием получившихся &amp;lt;math&amp;gt;p&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;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&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;n - 1&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф аогоритма. Однако следует отметить, что в большинстве случаев программисты не экономят на одном вызове операции сложения, а инициализируют начальное значение переменной нулём. В этом случае граф становится таким, как на рис.2 (n=24).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;thumb&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;thumbinner&amp;quot; style=&amp;quot;width:{{#expr: 2 * (700 + 35) + 3 * (3 - 1) + 8}}px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;gallery widths=700px heights=900px&amp;gt;&lt;br /&gt;
File:series-parallel dot product graph.png|Рисунок 1. Последовательно-параллельное вычисление скалярного произведения с экономией операций сложения&lt;br /&gt;
File:Series-parallel dot product graph straight.png|Рисунок 2. Последовательно-параллельное вычисление скалярного произведения без экономии операций сложения&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;thumbcaption&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления скалярного произведения массивов порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; последовательно-параллельным методом в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
* 1 ярус вычисления произведений,&lt;br /&gt;
* &amp;lt;math&amp;gt;k - 1&amp;lt;/math&amp;gt; ярусов суммирования по частям массивов (&amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; ветвей),&lt;br /&gt;
* &amp;lt;math&amp;gt;p - 1&amp;lt;/math&amp;gt; ярусов суммирования (одна последовательная ветвь).&lt;br /&gt;
&lt;br /&gt;
Таким образом, в параллельном варианте критический путь алгоритма  (и соответствующая ему высота ЯПФ) будет зависеть от произведённого разбиения массива на части. В оптимальном случае (&amp;lt;math&amp;gt;p = \sqrt{n}&amp;lt;/math&amp;gt;) высота ЯПФ будет равна &amp;lt;math&amp;gt; 2 \sqrt{n} - 1&amp;lt;/math&amp;gt;. При классификации по высоте ЯПФ, таким образом, последовательно-параллельный метод относится к алгоритмам &#039;&#039;со сложностью «корень квадратный»&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;«корень квадратный»&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массивы &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_i&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;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;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;корнем квадратным&#039;&#039; (отношение линейной к корню квадратному). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных почти столько же, сколько операций; если точнее - даже больше на 2)&#039;&#039;. При этом алгоритм полностью детерминирован при заданном разложении &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. Дуги информационного графа локальны. Для уменьшения ошибок округления режимом накопления в ряде алгоритмов, использующих скалярное произведение одинарной точности, оно вычисляется с двойной точностью. Впрочем, у последовательно-параллельного способа вычисления скалярного произведения и без режима накопления влияние ошибок округления «в среднем» меньше в &amp;lt;math&amp;gt;\sqrt{n}&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;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	DO  I = 1, P&lt;br /&gt;
		S (I) = A(K*(I-1)+1)*B(K*(I-1)+1)&lt;br /&gt;
		IF (I.LQ.P) THEN&lt;br /&gt;
			DO J = 2,K&lt;br /&gt;
				S(I)=S(I)+A(K*(I-1)+J)*B(K*(I-1)+J)&lt;br /&gt;
		             END DO&lt;br /&gt;
		ELSE&lt;br /&gt;
			DO J = 2,Q&lt;br /&gt;
				S(I)=S(I)+A(K*(I-1)+J)*B(K*(I-1)+J)&lt;br /&gt;
		             END DO&lt;br /&gt;
		END IF&lt;br /&gt;
	END DO&lt;br /&gt;
	SCP = S(1)&lt;br /&gt;
	DO I = 2, P&lt;br /&gt;
		SCP = SCP + S(I)&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно записать и аналогичные схемы, где суммирование будет проводиться в обратном порядке.  Подчеркнём, что граф алгоритма обеих схем — [[#Информационный граф|один и тот же]]! Тело первого цикла целиком может быть заменено вызовом функции скалярного произведения, если она реализована в последовательном варианте.&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Помимо [[#Особенности реализации последовательного алгоритма|выписанной выше простейшей реализации]], существуют более сложные коды, реализующие тот же алгоритм. Следует обратить внимание на то, что ряд реализаций (в том же BLAS) использует разложение &amp;lt;math&amp;gt;n&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Последовательно-параллельная группировка операций]]&lt;br /&gt;
[[Категория:Векторные операции]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dot product]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A0%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%80%D0%BC%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29720</id>
		<title>Равномерная норма вектора, вещественная версия, последовательно-параллельный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A0%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%80%D0%BC%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29720"/>
		<updated>2025-02-20T09:56:06Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Равномерная норма вектора, вещественная версия, последовательно-параллельный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(\sqrt{n})&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&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Равномерная норма вектора&#039;&#039;&#039; используется в качестве одной из базовых операций в широком круге методов — как для вычисления получаемой ошибки финальных результатов, так и для промежуточных вычислений.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; чисел.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: максимум абсолютной величины элементов массива.&lt;br /&gt;
&lt;br /&gt;
Формулы метода: для вектора &amp;lt;math&amp;gt;\vec{a}&amp;lt;/math&amp;gt; из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; элементов вычисляется выражение &amp;lt;math&amp;gt;\max\limits_i |a_i|&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;
&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;
Для вычисления равномерной нормы массива, состоящего из &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;N-1&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной сложности&#039;&#039; по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф алгоритма граф для случая &amp;lt;math&amp;gt;n = 24&amp;lt;/math&amp;gt;. Однако следует отметить, что в большинстве случаев программисты не экономят на одном вызове функции максимума, а инициализируют начальное значение переменной нулём. В этом случае граф становится таким, как на рис.2 (&amp;lt;math&amp;gt;n = 24&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;thumb&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;thumbinner&amp;quot; style=&amp;quot;width:{{#expr: 2 * (700 + 35) + 3 * (3 - 1) + 8}}px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;gallery widths=700px heights=900px&amp;gt;&lt;br /&gt;
File:series-parallel uniform norm graph without dummy max op.png|Рисунок 1. Вычисление равномерной нормы с экономией вызовов функции максимума&lt;br /&gt;
file:series-parallel uniform norm graph with dummy max op.png|Рисунок 2. Вычисление равномерной нормы без экономии вызовов функции максимума]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;thumbcaption&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательно-параллельный вариант вычисления равномерной нормы массива (в более экономном варианте) можно представить составленным из трёх частей. В первой из них выполняется &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; вычислений абсолютной величины в одном параллельном ярусе. Во второй части  параллельно выполняется &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; ветвей &amp;lt;math&amp;gt;N / p - 1&amp;lt;/math&amp;gt; длиной, выбирающих максимальные из частей массива. И, наконец, в третьей части последовательно, длиной &amp;lt;math&amp;gt;p - 1&amp;lt;/math&amp;gt;, выбирается максимум из максимумов. Таким образом, в получившемся алгоритме высота параллельной формы будет равна 1 операции вычисления функции ABS плюс &amp;lt;math&amp;gt;N / p + p - 2&amp;lt;/math&amp;gt; операций выбора максимума. Минимум будет достигнут при &amp;lt;math&amp;gt;p = \sqrt{N}&amp;lt;/math&amp;gt; и будет равен &amp;lt;math&amp;gt;2 \sqrt{N} - 2&amp;lt;/math&amp;gt; максимумов плюс одно вычисление абсолютной величины. В таком виде алгоритм должен быть отнесён к алгоритмам &#039;&#039;сложности порядка «корня квадратного»&#039;&#039; по высоте.  По ширине параллельной формы он за счёт отбрасывания знаков будет линеен, но можно, увеличив вдвое высоту, тоже сделать его &#039;&#039;сложности порядка «корня квадратного»&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n&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;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;корнем квадратным из размера&#039;&#039;. При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных почти столько же, сколько операций; если точнее — даже больше на 2)&#039;&#039;. При этом алгоритм полностью детерминирован. Дуги информационного графа локальны. Важной особенностью алгоритма является то, что его видоизменение и переход к другому графу (например, способу разбиения &amp;lt;math&amp;gt;N&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;
&lt;br /&gt;
В простейшем (входные данные — вектор, &amp;lt;math&amp;gt;p = \sqrt{N}&amp;lt;/math&amp;gt;) варианте на Фортране можно записать так:&lt;br /&gt;
	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	NORMX = ABS(A(1))&lt;br /&gt;
	DO J = 2, P&lt;br /&gt;
		NORMX = MAX( NORMX, ABS(A(J)))&lt;br /&gt;
	END DO&lt;br /&gt;
	DO I = 1, P-1&lt;br /&gt;
		NORMY = ABS (A(P*I+1))&lt;br /&gt;
		DO J = 2,P&lt;br /&gt;
			NORMY = MAX (NORMY, ABS (A(P*I+J)))&lt;br /&gt;
		END DO&lt;br /&gt;
		NORMX = MAX (NORMX, NORMY)&lt;br /&gt;
	END DO	&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
	  &lt;br /&gt;
В варианте с «холостым» выбором максимума запись такая:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	NORMX = 0.&lt;br /&gt;
	DO J = 1, P&lt;br /&gt;
		NORMX = MAX( NORMX, ABS(A(J)))&lt;br /&gt;
	END DO&lt;br /&gt;
	DO I = 1, P-1&lt;br /&gt;
		NORMY = 0.&lt;br /&gt;
		DO J = 1,P&lt;br /&gt;
			NORMY = MAX (NORMY, ABS (A(P*I+J)))&lt;br /&gt;
		END DO&lt;br /&gt;
		NORMX = MAX (NORMX, NORMY)&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&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;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Векторные операции]]&lt;br /&gt;
&lt;br /&gt;
[[en:Uniform norm of a vector: Real version, serial-parallel variant]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9D%D0%B0%D1%85%D0%BE%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0_%D1%81%D0%B4%D0%B2%D0%B0%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=29719</id>
		<title>Нахождение частных сумм элементов массива сдваиванием</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9D%D0%B0%D1%85%D0%BE%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0_%D1%81%D0%B4%D0%B2%D0%B0%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=29719"/>
		<updated>2025-02-20T08:40:26Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нахождение частных сумм элементов массива сдваиванием&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;\frac{n}{2} log_2 n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;\lceil \log_2 n \rceil&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Метод сдваивания&#039;&#039;&#039;&amp;lt;ref&amp;gt;Фролов А.В. Использование последовательно-параллельного метода для распараллеливания алгоритмов с ассоциативными операциями  // Принята в качестве доклада на первую объединенную международную конференцию &amp;quot;Суперкомпьютерные дни в России&amp;quot;, Москва, 28-29 сентября 2015 г.&amp;lt;/ref&amp;gt; используется в качестве быстрого варианта вычисления длинных последовательностей ассоциативных операций (например, массового получения частичных сумм). Получил распространение благодаря наименьшей из возможных высоте алгоритма. Данный алгоритм (нахождение частных сумм элементов массива сдваиванием) является только наиболее простой моделью для показа свойств алгоритма сдваивания.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;n&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;i&amp;lt;/math&amp;gt; принимает все значения от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Формулы метода: элементы на первом этапе алгоритма разбиваются на пары. В каждой из пар находится сумма составляющих её соседних элементов. &lt;br /&gt;
На следующем этапе на пары разбиваются уже эти суммы (и те элементы, которые не вошли в уже вычисленные суммы), и т. д.&lt;br /&gt;
По нахождению тех частных сумм, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; является степенью двойки, формулы повторяют [[Нахождение суммы элементов массива сдваиванием|алгоритм нахождения суммы элементов массива сдваиванием]].&lt;br /&gt;
Однако, кроме этого, для каждой пары (например, для нахождения суммы &amp;lt;math&amp;gt;x_i+...+x_{i+k}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;x_{i+k+1} +...+ x_{i+2k}&amp;lt;/math&amp;gt;)дополнительно вычисляются все частные суммы от &amp;lt;math&amp;gt;x_i+...+x_{i+k+1}&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;x_i+...+x_{i+2k-1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро метода сдваивания суммирования можно составить из элементарных бинарных (всего &amp;lt;math&amp;gt;\frac{n}{2} log_2 n&amp;lt;/math&amp;gt;) вычислений сумм.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как уже записано в описании ядра алгоритма, основную часть метода составляют элементарные бинарные (всего &amp;lt;math&amp;gt;\frac{n}{2} log_2 n&amp;lt;/math&amp;gt;) вычисления сумм.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В описанном виде суммирование сдваиванием не используют при последовательной реализации, поскольку кроме усложнения общей схемы алгоритма и резкого роста потребности в памяти, нужной для хранения промежуточных данных, сам по себе алгоритм содержит подавляющее большинство [[%D0%93%D0%BB%D0%BE%D1%81%D1%81%D0%B0%D1%80%D0%B8%D0%B9#.D0.98.D0.B7.D0.B1.D1.8B.D1.82.D0.BE.D1.87.D0.BD.D1.8B.D0.B5_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D1.8F|избыточных вычислений]]: по сравнению с последовательным алгоритмом нахождения частных сумм количество операций больше в &amp;lt;math&amp;gt;\frac{1}{2} log_2 n&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления суммы массива, состоящего из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; элементов, количество операций равно &amp;lt;math&amp;gt;\frac{n}{2} log_2 n&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейно-логарифмической сложности&#039;&#039; по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[File:DoublingPartUniv.png|thumb|center|600px|Рисунок 1. Граф алгоритма при n=8 c отображением входных данных. Синим обозначены входные, красным - выходные данные. Все вершины соответствуют операции сложения]]&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма изображён на рисунке.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления частичных сумм массива порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; методом сдваивания в параллельном варианте требуется последовательно выполнить &amp;lt;math&amp;gt;\lceil \log_2 n \rceil&amp;lt;/math&amp;gt; ярусов с одинаковым (&amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;) количеством операций суммирования.&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, метод сдваивания относится к алгоритмам с &#039;&#039;логарифмической сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n&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;i&amp;lt;/math&amp;gt; принимает все значения от &amp;lt;math&amp;gt;1&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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt; (отношение линейно-логарифмической к логарифмической). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — логарифмическая &amp;lt;math&amp;gt;\frac{1}{2} log_2 n&amp;lt;/math&amp;gt;. Это, однако, обусловлено избыточностью вычислений, реальная мощность - константа (1). При этом алгоритм полностью детерминирован. Дуги информационного графа нелокальны, от яруса к ярусу наблюдается показательный рост их длины, при любом размещении вершин графа (кроме дополнительных измерений в случае расположения вершин в гиперкубе).&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;
&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;
&lt;br /&gt;
Из-за своеобразия графа сдваивания лучше всего он отображается на архитектуру типа &amp;quot;гиперкуб&amp;quot;. Поэтому для архитектур с массовым параллелизмом представляется неизбежным рост накладных расходов и слабая масштабируемость алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные_статьи]]&lt;br /&gt;
[[Категория:Метод сдваивания]]&lt;br /&gt;
[[Категория:Алгоритмы с избыточными вычислениями]]&lt;br /&gt;
[[Категория:Векторные операции]]&lt;br /&gt;
&lt;br /&gt;
[[en:Parallel prefix scan algorithm using pairwise summation]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9D%D0%B0%D1%85%D0%BE%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81%D1%83%D0%BC%D0%BC%D1%8B_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0_%D1%81%D0%B4%D0%B2%D0%B0%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=29718</id>
		<title>Нахождение суммы элементов массива сдваиванием</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9D%D0%B0%D1%85%D0%BE%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81%D1%83%D0%BC%D0%BC%D1%8B_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0_%D1%81%D0%B4%D0%B2%D0%B0%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=29718"/>
		<updated>2025-02-19T13:26:24Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нахождение суммы элементов массива сдваиванием&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;log2n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Метод сдваивания&#039;&#039;&#039; используется в качестве быстрого варианта вычисления длинных последовательностей ассоциативных операций (например, массового суммирования). Получил распространение благодаря как наименьшей из возможных высоте алгортима, так и из-за ряда своих вычислительных характеристик, а также (в среде нечисленных алгоритмов) из-за своей рекурсивности, то есть лёгкости записи.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;n&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;
Вычислительное ядро метода сдваивания для суммирования можно составить как из элементарных бинарных (всего &amp;lt;math&amp;gt;n - 1&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;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления суммы массива, состоящего из &amp;lt;math&amp;gt;n/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;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной сложности&#039;&#039; по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф алгоритма. В данном случае выполнено суммирование 16 элементов массива.&lt;br /&gt;
Вершины, соответствующие входным данным, даны синим цветом, выходным данным - красным цветом.&lt;br /&gt;
&lt;br /&gt;
[[file:binary-tree-based summation graph.png|center|thumb|500px|Рисунок 1. Суммирование массива методом сдваивания]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для суммирования массива порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; методом сдваивания в параллельном варианте требуется последовательно выполнить &amp;lt;math&amp;gt;\lceil \log_2 n \rceil&amp;lt;/math&amp;gt; ярусов с убывающим (от &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;) количеством операций суммирования.&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, метод сдваивания относится к алгоритмам с &#039;&#039;логарифмической сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n&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;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &amp;lt;math&amp;gt;\frac{n}{\log_2 n}&amp;lt;/math&amp;gt; (отношение линейной к логарифмической). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных столько же, сколько операций)&#039;&#039;. При этом алгоритм полностью детерминирован. Дуги информационного графа нелокальны, от яруса к ярусу наблюдается показательный рост их длины, при любом размещении вершин графа. &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;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Метод сдваивания]]&lt;br /&gt;
[[Категория:Векторные операции]]&lt;br /&gt;
&lt;br /&gt;
[[En:Pairwise summation of numbers]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BB%D0%BE%D1%82%D0%BD%D1%8B%D1%85_%D0%BD%D0%B5%D0%BE%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86_(%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82)&amp;diff=29717</id>
		<title>Перемножение плотных неособенных матриц (последовательный вещественный вариант)</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BB%D0%BE%D1%82%D0%BD%D1%8B%D1%85_%D0%BD%D0%B5%D0%BE%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86_(%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82)&amp;diff=29717"/>
		<updated>2025-02-19T13:21:28Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Перемножение плотных неособенных матриц&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2mnl&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2ml&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;mn+nl&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;ml&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перемножение матриц&#039;&#039;&#039; - одна из базовых задач в алгоритмах линейной алгебры, широко применяется в большом количестве разных методов.&lt;br /&gt;
Здесь мы рассмотрим умножение &amp;lt;math&amp;gt;C = AB&amp;lt;/math&amp;gt;&amp;amp;nbsp; плотных неособенных матриц (последовательный вещественный вариант), то есть тот вариант, где никак не используются ни специальный вид матрицы, ни ассоциативные свойства операции сложения&amp;lt;ref&amp;gt;В.В.Воеводин, Ю.А.Кузнецов. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: плотная матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;), плотная матрица &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_{ij}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: плотная матрица &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Формулы метода:&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
c_{ij} = \sum_{k = 1}^{n} a_{ik} b_{kj}, \quad i \in [1, m], \quad j \in [1, l].&lt;br /&gt;
\end{align}&lt;br /&gt;
&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;l&amp;lt;/math&amp;gt;) вычислений умножения матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на столбцы матрицы &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, или (при более детальном рассмотрении), из множественных (всего их &amp;lt;math&amp;gt;ml&amp;lt;/math&amp;gt;) скалярных произведений строк матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на столбцы матрицы &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{k = 1}^{n} a_{ik} b_{kj}&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;ml&amp;lt;/math&amp;gt;) вычисления скалярных произведений строк матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на столбцы матрицы &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\sum_{k = 1}^{n} a_{ik} b_{kj}&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;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;  и для всех &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; выполняются&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;c_{ij} = \sum_{k = 1}^{n} a_{ik} b_{kj}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Особо отметим, что вычисления сумм вида &amp;lt;math&amp;gt;\sum_{k = 1}^{n} a_{ik} b_{kj}&amp;lt;/math&amp;gt; производят в режиме накопления прибавлением к текущему (временному) значению вычисляемого элемента матрицы &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt; произведений &amp;lt;math&amp;gt;a_{ik} b_{kj}&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, &#039;&#039;&#039;c возрастанием&#039;&#039;&#039; &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, вначале все элементы инициализируются нулями. При суммировании &amp;quot;по убыванию&amp;quot; общая схема принципиально не отличается и потому нами не рассматривается. Другие порядки выполнения суммирования приводят к изменению параллельных свойств алгоритма и будут рассматриваться нами в отдельных описаниях.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для умножения двух квадратных матриц порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; (т.е. при &amp;lt;math&amp;gt;m=n=l&amp;lt;/math&amp;gt;) в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* по &amp;lt;math&amp;gt;n^3&amp;lt;/math&amp;gt; умножений и сложений.&lt;br /&gt;
&lt;br /&gt;
Для умножения матрицы размером &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; строк на &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; столбцов на матрицу размером &amp;lt;math&amp;gt;m&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;mnl&amp;lt;/math&amp;gt; умножений и сложений.&lt;br /&gt;
 &lt;br /&gt;
При этом использование режима накопления требует совершения умножений и сложений в режиме двойной точности (или использования функции вроде DPROD в Фортране), что ещё больше увеличивает затраты во времени, требуемом для выполнения умножения матриц.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, алгоритм умножения матриц относится к алгоритмам &#039;&#039;с кубической сложностью&#039;&#039; (в случае неквадратных матриц - с &#039;&#039;трилинейной&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем [[глоссарий#Граф алгоритма|граф алгоритма]] как аналитически, так и в виде рисунка.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма умножения плотных матриц состоит из одной группы вершин, расположенной в целочисленных узлах трёхмерной области, соответствующая ей операция  &amp;lt;math&amp;gt;a+bc&amp;lt;/math&amp;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;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;:&lt;br /&gt;
** при &amp;lt;math&amp;gt;k = 1&amp;lt;/math&amp;gt; константа &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;; &lt;br /&gt;
** при &amp;lt;math&amp;gt;k &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине с координатами &amp;lt;math&amp;gt;i, j, k-1&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — элемент &#039;&#039;входных данных&#039;&#039;, а именно  &amp;lt;math&amp;gt;a_{ik}&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - элемент &#039;&#039;входных данных&#039;&#039; &amp;lt;math&amp;gt;b_{kj}&amp;lt;/math&amp;gt;; &lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является:&lt;br /&gt;
* при &amp;lt;math&amp;gt;k &amp;lt; n&amp;lt;/math&amp;gt; - &#039;&#039;промежуточным данным&#039;&#039; алгоритма;&lt;br /&gt;
* при &amp;lt;math&amp;gt;k = n&amp;lt;/math&amp;gt; - выходным данным &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[file:Dense mtrx product.png|thumb|center|800px|Рисунок 1. Умножение плотных матриц с отображением выходных данных]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
Интерактивное изображение графа алгоритма без входных и выходных данных для случая перемножения двух квадратных матриц порядка 3 и 4&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{#widget:Algoviewer&lt;br /&gt;
|url=mat_mul/mat_mul_3/Algo_view_matrix3.html&lt;br /&gt;
|width=600&lt;br /&gt;
|height=400&lt;br /&gt;
|border=1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{#widget:Algoviewer&lt;br /&gt;
|url=mat_mul/mat_mul_4/Algo_view_matrix4.html&lt;br /&gt;
|width=600&lt;br /&gt;
|height=400&lt;br /&gt;
|border=1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для алгоритма умножения квадратных матриц порядка n в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* по &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений (в каждом из ярусов — &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
Для умножения матрицы размером &amp;lt;math&amp;gt;m&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;l&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;ml&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
При этом использование режима накопления требует совершения умножений и вычитаний в режиме двойной точности, а в параллельном варианте это означает, что практически все промежуточные вычисления для выполнения алгоритма в режиме накопления должны быть двойной точности. В отличие от последовательного варианта это означает некоторое увеличение требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матриц относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;квадратичной&#039;&#039; (для квадратных матриц) или &#039;&#039;билинейной&#039;&#039; (для матриц общего вида).&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;), матрица &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_{ij}&amp;lt;/math&amp;gt;)).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;mn+nl&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: матрица &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;c_{ij}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;ml&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;квадратичным&#039;&#039; или &#039;&#039;билинейным&#039;&#039; (отношение кубической или трилинейной к линейной). &lt;br /&gt;
&lt;br /&gt;
При этом вычислительная мощность алгоритма умножения матриц, как отношение числа операций к суммарному объему входных и выходных данных – &#039;&#039;линейно&#039;&#039;.&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;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         &lt;br /&gt;
	DO  I = 1, M&lt;br /&gt;
        DO  J = 1, L&lt;br /&gt;
		S = 0.&lt;br /&gt;
		DO  K = 1, N&lt;br /&gt;
			S = S + DPROD(A(I,K), B(K,J))&lt;br /&gt;
		END DO	&lt;br /&gt;
	        C(I, J) = S&lt;br /&gt;
        END DO&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При этом для реализации режима накопления переменная &amp;lt;math&amp;gt;S&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
[[Категория:Матричные операции]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dense matrix multiplication (serial version for real matrices)]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%85%D0%B5%D0%BC%D0%B0_%D0%93%D0%BE%D1%80%D0%BD%D0%B5%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29716</id>
		<title>Схема Горнера, вещественная версия, последовательный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%85%D0%B5%D0%BC%D0%B0_%D0%93%D0%BE%D1%80%D0%BD%D0%B5%D1%80%D0%B0,_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F,_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=29716"/>
		<updated>2025-02-19T13:14:05Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Схема Горнера для деления многочлена n-й степени на приведённый двучлен&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;11n-16&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;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
==== Решаемая задача ====&lt;br /&gt;
&lt;br /&gt;
Схема Горнера&amp;lt;ref&amp;gt;Н.Я. Виленкин, Р.С. Гутер, С.И. Шварцбурд, Б.В. Овчинский, В.Г. Ашкинузе. Алгебра. Учебное пособие для 9-10 классов средних школ с математической специализацией. М.: Просвещение, 1972&amp;lt;/ref&amp;gt; решает задачу деления многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; с известными коэффициентами на двучлен &amp;lt;math&amp;gt;x - \alpha&amp;lt;/math&amp;gt;. В качестве результатов выступают коэффициенты многочлена &amp;lt;math&amp;gt;Q_{n - 1}(x)&amp;lt;/math&amp;gt; из соотношения&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;P_n(x) - P_n(\alpha) = (x - \alpha) Q_{n - 1}(x)&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
а также &amp;lt;math&amp;gt;P_n(\alpha)&amp;lt;/math&amp;gt; (значение многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
К сожалению, зачастую в учебной литературе схему Горнера сводят к вычислению значения многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Общая схема ====&lt;br /&gt;
&lt;br /&gt;
Фактически схема Горнера реализует «деление уголком» многочлена на двучлен &amp;lt;math&amp;gt;x - \alpha&amp;lt;/math&amp;gt;, с нахождением остатка, который, по теореме Безу, равен значению многочлена &amp;lt;math&amp;gt;P_n(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: одномерный массив &amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt; чисел &amp;lt;math&amp;gt;a_k&amp;lt;/math&amp;gt; и скаляр &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: одномерный массив &amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt; чисел &amp;lt;math&amp;gt;b_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Формулы метода с выводом: из соотношения &lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;P_n(x) - P_n(\alpha) = (x - \alpha) Q_{n - 1}(x)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
если записать оба многочлена в каноническом виде&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
P_n(x)       &amp;amp; = a_0 x^n+ a_1 x^{n - 1} + \dots + a_{n - 1} x + a_n, \\&lt;br /&gt;
Q_{n - 1}(x) &amp;amp; = b_0 x^{n - 1} + b_1 x^{n - 2} + \dots + b_{n - 2} x + b_{n - 1}&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и приписать «свободному» &amp;lt;math&amp;gt;b_n&amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt;P_n(\alpha)&amp;lt;/math&amp;gt;, то, при подстановке многочленов в каноническом виде в исходное соотношение и приравнивании коэффициентов равных степеней, в качестве решения получается&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
b_0 &amp;amp; = a_0, \\&lt;br /&gt;
b_k &amp;amp; = a_k + \alpha b_{k - 1}, \quad k = 1, \dots, n&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
что и является &#039;&#039;&#039;формулами схемы Горнера&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро схемы Горнера в последовательном варианте можно представить в качестве последовательного набора &amp;lt;math&amp;gt;n&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;
Формулы метода описаны выше. Последовательность исполнения — по возрастанию индекса &#039;&#039;k&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления схемы Горнера для многочлена степени &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, количество операций умножения равно количеству операций сложения и равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. Поэтому алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по количеству последовательных операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
На рис.1 изображён граф алгоритма для &amp;lt;math&amp;gt;n = 9&amp;lt;/math&amp;gt;. Как видно, граф чисто последовательный. Ввод и вывод обозначен только для начального коэффициента и значения многочлена. Op - операция &amp;quot;умножить входное данное на скаляр и прибавить к другому данному&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[file:Basic sequental algorithm graph.png|center|thumb|800px|Рисунок 1. Схема Горнера: последовательная версия]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательный вариант вычисления схемы Горнера не имеет ресурсов параллелизма. Его ярусно-параллельная форма (ЯПФ) — единственна и совпадает с последовательным алгоритмом. Таким образом, в получившемся алгоритме высота параллельной формы будет равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций умножения плюс &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций сложения. В таком виде алгоритм должен быть отнесён к алгоритмам &#039;&#039;линейной&#039;&#039; сложности по высоте параллельной формы. Ширина параллельной формы равна &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;, что даёт нам &#039;&#039;постоянную&#039;&#039; сложность по ширине параллельной формы.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Входные данные: массив &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; с номерами от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;), скаляр &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения: отсутствуют.&lt;br /&gt;
&lt;br /&gt;
Объём входных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n + 2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: массив &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_k&amp;lt;/math&amp;gt; с номерами от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Объём выходных данных: &amp;lt;nowiki/&amp;gt;&amp;lt;math&amp;gt;n + 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;константой&#039;&#039; (1). При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных — всего-навсего &#039;&#039;1 (входных и выходных данных даже на 1 больше, чем количество операций)&#039;&#039;. При этом алгоритм полностью детерминирован. Дуги информационного графа локальны. По устойчивости схема Горнера оптимальна для вычисления значения многочлена с известными коэффициентами.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
На Фортране схему Горнера можно записать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
	b(0) = a(0)&lt;br /&gt;
	DO I = 1, N&lt;br /&gt;
		b(I) = a(I)+b(I-1)*alpha&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&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;b&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en: Horners method]]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
[[Категория:Алгоритмы с низким уровнем параллелизма]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BB%D0%BE%D1%82%D0%BD%D0%BE%D0%B9_%D0%BD%D0%B5%D0%BE%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80_(%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82)&amp;diff=29715</id>
		<title>Умножение плотной неособенной матрицы на вектор (последовательный вещественный вариант)</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BB%D0%BE%D1%82%D0%BD%D0%BE%D0%B9_%D0%BD%D0%B5%D0%BE%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80_(%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82)&amp;diff=29715"/>
		<updated>2025-02-19T13:12:58Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение плотной неособенной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;2mn&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2m&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;mn+m&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Frolov|А.В.Фролов]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]]), [[Участник:Teplov|А.М.Теплов]] (раздел [[#Масштабируемость алгоритма и его реализации|2.4]])&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Умножение матрицы на вектор&#039;&#039;&#039; - одна из базовых задач в алгоритмах линейной алгебры, широко применяется в большом количестве разных методов.&lt;br /&gt;
Здесь мы рассмотрим умножение &amp;lt;math&amp;gt;y = Ax&amp;lt;/math&amp;gt; плотной неособенной матрицы на вектор (последовательный вещественный вариант)&amp;lt;ref&amp;gt;В.В.Воеводин, Ю.А.Кузнецов. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt;, то есть тот вариант, где никак не используются ни специальный вид матрицы, ни ассоциативные свойства операции сложения.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Исходные данные: плотная матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;), умножаемый на неё вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор решения &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;y_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Формулы метода:&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
y_{i} = \sum_{j = 1}^{n} a_{ij} x_{j}, \quad i \in [1, m].&lt;br /&gt;
\end{align}&lt;br /&gt;
&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;m&amp;lt;/math&amp;gt;) вычислений скалярных произведений строк матрицы &amp;lt;math&amp;gt;A&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; \sum_{j = 1}^{n} a_{ij} x_{j}&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;m&amp;lt;/math&amp;gt;) вычисления скалярных произведений строк матрицы &amp;lt;math&amp;gt;A&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; \sum_{j = 1}^{n} a_{ij} x_{j}&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;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; по возрастанию выполняются&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_{i} = \sum_{j = 1}^{n} a_{ij} x_{j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Особо отметим, что вычисления сумм вида &amp;lt;math&amp;gt;\sum_{j = 1}^{n} a_{ij} x_{j}&amp;lt;/math&amp;gt; производят в режиме накопления прибавлением к текущему (временному) значению вычисляемой компоненты вектора &amp;lt;math&amp;gt;y_{i}&amp;lt;/math&amp;gt; произведений &amp;lt;math&amp;gt;a_{ij} x_{j}&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, &#039;&#039;&#039;c возрастанием&#039;&#039;&#039; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, вначале все компоненты инициализируются нулями. При суммировании &amp;quot;по убыванию&amp;quot; общая схема принципиально не отличается и потому нами не рассматривается. Другие порядки выполнения суммирования приводят к изменению параллельных свойств алгоритма и будут рассматриваться нами в отдельных описаниях.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для умножения квадратной матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; (т.е. при &amp;lt;math&amp;gt;m=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;m&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;mn&amp;lt;/math&amp;gt; умножений и сложений.&lt;br /&gt;
 &lt;br /&gt;
При этом использование режима накопления требует совершения умножений и сложений в режиме двойной точности (или использования функции вроде DPROD в Фортране), что ещё больше увеличивает затраты во времени, требуемом для выполнения умножения матрицы на вектор.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с квадратической сложностью&#039;&#039; (в случае неквадратной матрицы - с &#039;&#039;билинейной&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем [[глоссарий#Граф алгоритма|граф алгоритма]] как аналитически, так и в виде рисунка.&lt;br /&gt;
&lt;br /&gt;
[[Файл:YeqAX.png|500px|thumb|center|Рисунок 1. Граф последовательного умножения плотной матрицы на вектор с отображением входных и выходных данных]]&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма умножения плотной матрицы на вектор состоит из одной группы вершин, расположенной в целочисленных узлах двумерной области, соответствующая ей операция  &amp;lt;math&amp;gt;a+bc&amp;lt;/math&amp;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;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;:&lt;br /&gt;
** при &amp;lt;math&amp;gt;j = 1&amp;lt;/math&amp;gt; константа &amp;lt;math&amp;gt;0.&amp;lt;/math&amp;gt;; &lt;br /&gt;
** при &amp;lt;math&amp;gt;j &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине с координатами &amp;lt;math&amp;gt;i, j-1&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — элемент &#039;&#039;входных данных&#039;&#039;, а именно  &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - элемент входных данных &amp;lt;math&amp;gt;x_{j}&amp;lt;/math&amp;gt;; &lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является:&lt;br /&gt;
* при &amp;lt;math&amp;gt;j &amp;lt; n&amp;lt;/math&amp;gt; - &#039;&#039;промежуточным данным&#039;&#039; алгоритма;&lt;br /&gt;
* при &amp;lt;math&amp;gt;j = n&amp;lt;/math&amp;gt; - выходным данным.&lt;br /&gt;
&lt;br /&gt;
Описанный граф можно посмотреть на рисунке, выполненном для случая &amp;lt;math&amp;gt;m = 4, n = 5&amp;lt;/math&amp;gt;. Здесь вершины обозначены голубым цветом. Изображена подача только входных данных из вектора &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;, подача элементов матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, идущая во все вершины, на рисунке не представлена.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для алгоритма умножения квадратной матрицы на вектор порядка n в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&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;m&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&amp;lt;/math&amp;gt; ярусов умножений и сложений (в каждом из ярусов — &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
При этом использование режима накопления требует совершения умножений и сложений в режиме двойной точности, а в параллельном варианте это означает, что практически все промежуточные вычисления для выполнения алгоритма в режиме накопления должны быть двойной точности. В отличие от последовательного варианта это означает некоторое увеличение требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;), вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;mn+n&amp;lt;/math&amp;gt; . &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: вектор &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;y_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;m&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;
При этом вычислительная мощность алгоритма умножения матрицы на вектор, как отношение числа операций к суммарному объему входных и выходных данных – всего лишь &#039;&#039;константа&#039;&#039;.&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;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         &lt;br /&gt;
	DO  I = 1, M&lt;br /&gt;
		S = 0.&lt;br /&gt;
		DO  J = 1, N&lt;br /&gt;
			S = S + DPROD(A(I,J), X(J))&lt;br /&gt;
		END DO	&lt;br /&gt;
	        Y(I) = S&lt;br /&gt;
	END DO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При этом для реализации режима накопления переменная &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; должна быть двойной точности.&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:mv mult 1.PNG|thumb|center|700px|Рисунок 2. Умножение плотной матрицы на вектор. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис.2 представлен профиль обращений в память для реализации умножения плотной матрицы на вектор. В данном алгоритме задействовано три массива. Выделенный зеленым фрагмент 1 образован обращениями к результирующему вектору; фрагмент 2 – обращениями к исходному вектору; остальные обращения (фрагмент 3) выполняются к матрице, на которую умножается исходный вектор.&lt;br /&gt;
&lt;br /&gt;
Если посмотреть на исходный код, становится понятным, что каждый фрагмент устроен очень просто:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
for(int i = 0; i &amp;lt; size; i++)&lt;br /&gt;
for(int j = 0; j &amp;lt; size; j++)&lt;br /&gt;
vec_out[i] += matrix[i][j] * vec_in[j];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что фрагмент 1 (обращения к массиву vec_out) состоит из последовательного перебора всех элементов вектора, только к каждому элементу происходит подряд size обращений. Во фрагменте 2 (массив vec_in) выполняется обычный последовательный перебор, который затем повторяется size раз. Фрагмент 3 также представляет собой последовательный перебор всех элементов матрицы, который выполняется только один раз.&lt;br /&gt;
&lt;br /&gt;
Самой высокой локальностью обладает фрагмент 1 из-за повторяющихся подряд обращений к одним и тем же элементам. Однако фрагмент 2 также обладает высокой как пространственной, так и временной локальностью, поскольку число повторных проходов достаточно велико. Фрагмент 3, как и остальные, характеризуется высокой пространственной локальностью (из-за последовательного перебора), однако очень низкой временной локальностью – повторные обращения в нем просто отсутствуют.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [https://gitlab.srcc.msu.ru/vadim/locality/blob/master/benchmarks/d_matrix_vect_mult/d_matrix_vect_mult.h здесь] (функция Kernel). Условия запуска описаны [https://gitlab.srcc.msu.ru/vadim/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис.3 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Можно увидеть, что производительность данной программы очень высока, даже немного выше, чем производительность теста Linpack. Одна из основных причин этому – очень высокая локальность обращений к векторам.&lt;br /&gt;
&lt;br /&gt;
[[file:mv mult daps ru.PNG|thumb|center|700px|Рисунок 3. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис.4 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Можно увидеть, что, согласно данной оценке, локальность реализации умножения матрицы на вектор высока, хотя и не среди первых значений. Однако можно заметить, что полученное значение лишь совсем немного ниже оценки cvg для, например, реализации метода Гаусса или лучших вариантов перемножения матрицы. &lt;br /&gt;
&lt;br /&gt;
[[file:mv mult cvg.PNG|thumb|center|700px|Рисунок 4. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
==== Масштабируемость алгоритма ====&lt;br /&gt;
==== Масштабируемость реализации алгоритма ====&lt;br /&gt;
[[file:Масштабируемость перемножения матрицы и вектора производительность.png|thumb|center|700px|Рисунок 5. Параллельная реализация произведения матрицы на вектор Максимальная производительность. ]]&lt;br /&gt;
[[file:Масштабируемость перемножения матрицы и вектора эффективность.png|thumb|center|700px|Рисунок 6. Параллельная реализация произведения матрицы на вектор Максимальная эффективность. ]]&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [4 : 256]&lt;br /&gt;
*	размерность матрицы [1024 : 51200]&lt;br /&gt;
Эффективность выполнения реализации алгоритма&lt;br /&gt;
*	Минимальная эффективность 0,02%&lt;br /&gt;
*	Максимальная эффективность 9,55%&lt;br /&gt;
Оценка масштабируемости&lt;br /&gt;
*	По числу процессов: -0.01517 – при увеличении числа процессов эффективность убывает достаточно интенсивно на всей рассмотренной области изменений параметров запуска. Уменьшение эффективности на рассмотренной области работы параллельной программы звязано с увеличением числа пересылок с ростом числа процессов и как следствие ростом накладных расходов на организацию вычислений. Основной вклад в значение эффективности вносит область с малым числом процессов и малой задачей, там эффективность достигает максимума в 9,5%. Далее эффективность очень резко падает до уровня около 1% Присутствует область, на которой при увеличении числа процессов эффективность возрастает, но при дальнейшем росте продолжает снижаться. Это скорее всего объясняется декомпозицей данных, при которой наступает момент, когда размер матрицы позволяет блокам укладываться в КЭШ-память. Так же это подтверждает проявление этого явления, но со смещением по числу процессов, и при увеличении вычислительной сложности задачи.&lt;br /&gt;
*	По размеру задачи: -0.0014 – при увеличении размера задачи эффективность в целом уменьшается по рассматриваемой области, хотя и менее интенсивно, чем при увеличении числа процессов. Снижение эффективности объясняется тем, что при росте вычислительной сложности существенно возрастают объемы передаваемых данных. При увеличении размера данных наступает момент резкого снижения эффективности с значений около 1% к долям процента и минимуму. С увеличением числа процессоров такой переход появляется на большем объеме данных. Это свидетельствует о том, что присутствует момент, когда данных слишком много и эффективность работы с ними становится значительно ниже, но чем больше имеется процессов, там позже наступает такой момент декомпозиции. Присутствует область возрастания эффективности, на всех рассмотренных размерах матрицы. Это объясняется тем, что при малом размере задачи данные хорошо укладываются в КЭШ память, что приводит к высокой эффективности работы приложения при малом размере задачи. При дальнейшем увеличении размера эффективность уменьшается при выходе за границы КЭШ-памяти. &lt;br /&gt;
*	По двум направлениям: -0.0001546 – при рассмотрении увеличения, как вычислительной сложности, так и числа процессов по всей рассмотренной области значений уменьшается, интенсивность уменьшения эффективности не очень высока. В совокупности с тем фактом, что разница между максимальной и минимальной эффективностью на рассмотренной области значений параметров составляет около 9% говорит о том, что уменьшение эффективности по всей области довольно равномерное, но интенсивно лишь в не очень больших участках по площади. На остальной области значений параметров изменения эффективности не столь значительны и находятся на приблизительно одном и том же уровне.&lt;br /&gt;
&lt;br /&gt;
[https://gitlab.srcc.msu.ru/alex-teplov/Scalability/blob/master/matrix_vector_mult/mpi_mat_vect_time.c Реализация алгоритма на языке C]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
[[Категория:Матрично-векторные операции]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dense matrix-vector multiplication]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2&amp;diff=29628</id>
		<title>Структура описания свойств алгоритмов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2&amp;diff=29628"/>
		<updated>2024-12-04T10:32:04Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Данный документ содержит описание схемы, по которой предлагается описывать свойства и структуру каждого алгоритма. Описание состоит из двух частей. В [[#ЧАСТЬ. Свойства и структура алгоритмов|первой части]] описываются собственно алгоритмы и их свойства, а [[#ЧАСТЬ. Программная реализация алгоритмов|вторая]] посвящена описанию особенностей их программной реализации с учетом конкретных программно-аппаратных платформ. Такое деление на части сделано для того, чтобы машинно-независимые свойства алгоритмов, которые определяют качество их реализации на параллельных вычислительных системах, были бы выделены и описаны отдельно от множества вопросов, связанных с последующими этапами программирования алгоритмов и исполнения результирующих программ. &lt;br /&gt;
&lt;br /&gt;
Общая схема описания алгоритмов имеет следующий вид:&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
Свойства алгоритмов никак не зависят от вычислительных систем, и с этой точки зрения данная часть AlgoWiki имеет безусловную собственную ценность. Описание алгоритма делается один раз, после чего многократно используется для его реализации в различных программно-аппаратных средах. Несмотря на то, что в данной части мы рассматриваем лишь машинно-независимые свойства алгоритмов, соображения, важные на этапе реализации, или же ссылки на соответствующие пункты [[#ЧАСТЬ. Программная реализация алгоритмов|части II AlgoWiki]], здесь также вполне уместны.&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;
В описываемом алгоритме выделяется и описывается [[глоссарий#Вычислительное ядро|&#039;&#039;вычислительное ядро&#039;&#039;]], т.е. та часть алгоритма, на которую приходится основное время работы алгоритма. Если в алгоритме несколько вычислительных ядер, то отдельно описывается каждое ядро. Описание может быть сделано в достаточно произвольной форме: словесной или с использованием языка математических формул. Вычислительное ядро может полностью совпадать с описываемым алгоритмом.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Если алгоритм использует в качестве составных частей другие алгоритмы, то это указывается в данном разделе. Если в дальнейшем имеет смысл описывать алгоритм не в максимально детализированном виде (т.е. на уровне арифметических операций), а давать только его макроструктуру, то здесь описывается структура и состав макроопераций. Если в других разделах описания данного алгоритма в рамках AlgoWiki используются введенные здесь макрооперации, то здесь даются пояснения, необходимые для однозначной интерпретации материала. Типичные варианты макроопераций, часто встречающиеся на практике: нахождение суммы элементов вектора, скалярное произведение векторов, умножение  матрицы на вектор, решение системы линейных уравнений малого порядка, сортировка, вычисление значения функции в некоторой точке, поиск минимального значения в массиве, транспонирование матрицы, вычисление обратной матрицы и многие другие.&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;
&lt;br /&gt;
Описание схемы реализации вполне может содержать и словесные пояснения, отражающие какие-либо тонкие нюансы самого алгоритма или его реализации. Уже в данном разделе можно сказать про возможный компромисс между объемом требуемой оперативной памяти и временем работы алгоритма, между используемыми структурами данных и степенью доступного параллелизма. В частности, часто возникает ситуация, когда можно ввести дополнительные временные массивы или же отказаться от использования специальных компактных схем хранения данных, увеличивая степень доступного параллелизма.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
В данном разделе описания свойств алгоритма приводится оценка его [[глоссарий#Последовательная сложность|&#039;&#039;последовательной сложности&#039;&#039;]], т.е. числа операций, которые нужно выполнить при последовательном исполнении алгоритма (в соответствии с [[#Описание схемы реализации последовательного алгоритма|п.1.5]]). Для разных алгоритмов понятие операции, в терминах которой оценивается его сложность, может существенно различаться. Это могут быть операции для работы с вещественными числами, целыми числами, поразрядные операции, обращения в память, обновления элементов массива, элементарные функции, макрооперации и другие. В LU-разложении преобладают арифметические операции над вещественными числами, а для транспонирования матриц важны лишь обращения к памяти: это и должно найти отражение в описании.&lt;br /&gt;
&lt;br /&gt;
Если выбор конкретного типа операций для оценки сложности алгоритма не очевиден, то нужно привести обоснование возможных вариантов. В некоторых случаях можно приводить оценку не всего алгоритма, а лишь его вычислительного ядра: в таком случае это нужно отметить, сославшись [[#Общее описание алгоритма|на п.1.1]]. &lt;br /&gt;
&lt;br /&gt;
Например, сложность алгоритма суммирования элементов вектора сдваиванием равна &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;. Сложность быстрого преобразования Фурье (базовый алгоритм Кули-Тьюки) для векторов с длиной, равной степени двойки – &amp;lt;math&amp;gt;n\log_2n&amp;lt;/math&amp;gt; операций комплексного сложения и &amp;lt;math&amp;gt;(n\log_2n)/2&amp;lt;/math&amp;gt; операций комплексного умножения. Сложность базового алгоритма разложения Холецкого (точечный вариант для плотной симметричной и положительно-определенной матрицы) это &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вычислений квадратного корня, &amp;lt;math&amp;gt;n(n-1)/2&amp;lt;/math&amp;gt; операций деления, по &amp;lt;math&amp;gt;(n^3-n)/6&amp;lt;/math&amp;gt; операций умножения и сложения (вычитания).&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Это очень важный раздел описания. Именно здесь можно показать (увидеть) как устроена параллельная структура алгоритма, для чего приводится описание и изображение его информационного графа ([[глоссарий#Граф алгоритма|&#039;&#039;графа алгоритма&#039;&#039;]] &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot;&amp;gt;Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. - СПб.: БХВ-Петербург, 2002. - 608 с. &amp;lt;/ref&amp;gt;). Для рисунков с изображением графа будут составлены рекомендации по их формированию, чтобы все информационные графы, внесенные в энциклопедию, можно было бы воспринимать и интерпретировать одинаково. Дополнительно можно привести полное параметрическое  описание графа в терминах покрывающих функций &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Интересных вариантов для отражения информационной структуры алгоритмов много. Для каких-то алгоритмов нужно показать максимально подробную структуру, а иногда важнее макроструктура. Много информации несут разного рода проекции информационного графа, выделяя его регулярные составляющие и одновременно скрывая несущественные детали. Иногда оказывается полезным показать последовательность в изменении графа при изменении значений внешних переменных  (например, размеров матриц): мы часто ожидаем &amp;quot;подобное&amp;quot; изменение информационного графа, но это изменение не всегда очевидно на практике.  &lt;br /&gt;
&lt;br /&gt;
В целом, задача изображения графа алгоритма весьма нетривиальна. Начнем с того, что это потенциально бесконечный граф, число вершин и дуг которого определяется значениями внешних переменных, а они могут быть весьма и весьма велики. В такой ситуации, как правило, спасают упомянутые выше соображения подобия, делающие графы для разных значений внешних переменных &amp;quot;похожими&amp;quot;: почти всегда достаточно привести лишь один граф небольшого размера, добавив, что графы для остальных значений будут устроены &amp;quot;точно также&amp;quot;. На практике, увы, не всегда все так просто, и здесь нужно быть аккуратным.&lt;br /&gt;
&lt;br /&gt;
Далее, граф алгоритма - это потенциально многомерный объект. Наиболее естественная система координат для размещения вершин и дуг информационного графа опирается на структуру вложенности циклов в реализации алгоритма. Если глубина вложенности циклов не превышает трех, то и граф размещается в привычном трехмерном пространстве, однако для более сложных циклических конструкций с глубиной вложенности 4 и больше необходимы специальные методы представления и изображения графов. &lt;br /&gt;
&lt;br /&gt;
В данном разделе AlgoWiki могут использоваться многие интересные возможности, которые еще подлежат обсуждению: возможность повернуть граф при его отображении на экране компьютера для выбора наиболее удобного угла обзора, разметка вершин по типу соответствующим им операций, отражение [[глоссарий#Ярусно-параллельная форма графа алгоритма|&#039;&#039;ярусно-параллельной формы графа&#039;&#039;]] и другие. Но в любом случае нужно не забывать главную задачу данного раздела - показать информационную структуру алгоритма так, чтобы стали понятны все его ключевые особенности, особенности параллельной структуры, особенности множеств дуг, участки регулярности и, напротив, участки с недерминированной структурой, зависящей от входных данных. &lt;br /&gt;
&lt;br /&gt;
На рис.1 показана информационная структура алгоритма умножения матриц, на рис.2 - информационная структура одного из вариантов алгоритма решения систем линейных алгебраических уравнений с блочно-двухдиагональной матрицей.&lt;br /&gt;
&lt;br /&gt;
[[file:Fig1.svg|thumb|center|300px|Рис.1. Информационная структура алгоритма умножения матриц]]&lt;br /&gt;
[[file:Fig2.svg|thumb|center|300px|Рис.2. Информационная структура одного из вариантов алгоритма решения систем линейных алгебраических уравнений с блочно-двухдиагональной матрицей]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Здесь приводится оценка [[глоссарий#Параллельная сложность|&#039;&#039;параллельной сложности&#039;&#039;]] алгоритма: числа шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых процессоров (функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической ярусно-параллельной формы &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt;. Необходимо указать, в терминах каких операций дается оценка. Необходимо описать сбалансированность параллельных шагов по числу и типу операций, что определяется шириной ярусов канонической ярусно-параллельной формы и составом операций на ярусах. &lt;br /&gt;
&lt;br /&gt;
Параллелизм в алгоритме часто имеет естественную иерархическую структуру. Этот факт очень полезен на практике, и его необходимо отразить в описании. Как правило, подобная иерархическая структура параллелизма хорошо отражается в последовательной реализации алгоритма через циклический профиль результирующей программы (конечно же, с учетом графа вызовов), поэтому циклический профиль ([[#Описание схемы реализации последовательного алгоритма|п.1.5]]) вполне  может быть использован и для отражения ресурса параллелизма.&lt;br /&gt;
&lt;br /&gt;
Для описания ресурса параллелизма алгоритма (ресурса параллелизма информационного графа) необходимо указать ключевые параллельные ветви в терминах [[глоссарий#Конечный параллелизм|&#039;&#039;конечного&#039;&#039;]] и [[глоссарий#Массовый параллелизм|&#039;&#039;массового&#039;&#039;]] параллелизма. Далеко не всегда ресурс параллелизма выражается просто, например, через [[глоссарий#Кооодинатный параллелизм|&#039;&#039;координатный параллелизм&#039;&#039;]] или, что то же самое, через независимость итераций некоторых циклов (да-да-да, циклы - это понятие, возникающее лишь на этапе реализации, но здесь все так связано… В данном случае, координатный параллелизм означает, что информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей). С этой точки зрения, не менее важен и ресурс [[глоссарий#Скошенный параллелизм|&#039;&#039;скошенного параллелизма&#039;&#039;]]. В отличие от координатного параллелизма, скошенный параллелизм намного сложнее использовать на практике, но знать о нем необходимо, поскольку иногда других вариантов и не остается: нужно оценить потенциал алгоритма, и лишь после этого, взвесив все альтернативы, принимать решение о конкретной параллельной реализации. Хорошей иллюстрацией может служить алгоритм, структура которого показана на рис.2: координатного параллелизма нет, но есть параллелизм скошенный, использование которого снижает сложность алгоритма с &amp;lt;math&amp;gt;n\times m&amp;lt;/math&amp;gt; в последовательном случае до &amp;lt;math&amp;gt;(n+m-1)&amp;lt;/math&amp;gt; в параллельном варианте.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим алгоритмы, последовательная сложность которых уже оценивалась в [[#Последовательная сложность алгоритма|п.1.6]]. Параллельная сложность алгоритма суммирования элементов вектора сдваиванием равна &amp;lt;math&amp;gt;\log_2n&amp;lt;/math&amp;gt;, причем число операций на каждом ярусе убывает с &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;. Параллельная сложность быстрого преобразования Фурье (базовый алгоритм Кули-Тьюки) для векторов с длиной, равной степени двойки - &amp;lt;math&amp;gt;\log_2n&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;(n-1)&amp;lt;/math&amp;gt; шагов для операций умножения и сложения.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
В данном разделе необходимо описать объем, структуру, особенности и свойства входных и выходных данных алгоритма: векторы, матрицы, скаляры, множества, плотные или разреженные структуры данных, их объем. Полезны предположения относительно диапазона значений или структуры, например, диагональное преобладание в структуре входных матриц, соотношение между размером матриц по отдельным размерностям, большое число матриц очень малой размерности, близость каких-то значений к машинному нулю, характер разреженности матриц и другие.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Описываются прочие свойства алгоритма, на которые имеет смысл обратить внимание на этапе реализации. Как и ранее, никакой привязки к конкретной программно-аппаратной платформе не предполагается, однако вопросы реализации в проекте AlgoWiki всегда превалируют, и необходимость обсуждения каких-либо свойств алгоритмов определяется именно этим.&lt;br /&gt;
&lt;br /&gt;
Весьма полезным является &#039;&#039;соотношение последовательной и параллельной сложности&#039;&#039; алгоритма. Оба понятия мы рассматривали ранее, но здесь делается акцент на том выигрыше, который теоретически может дать параллельная реализация алгоритма. Не менее важно описать и те сложности, которые могут возникнуть в процессе получения параллельной версии алгоритма. &lt;br /&gt;
&lt;br /&gt;
[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]] алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных. Несмотря на простоту данного понятия, это значение исключительно полезно на практике: чем выше  вычислительная мощность, тем меньше накладных расходов вызывает перемещение данных для их обработки, например, на сопроцессоре, ускорителе или другом узле кластера. Например, вычислительная мощность скалярного произведения двух векторов равна всего лишь &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;, а вычислительная мощность алгоритма умножения двух квадратных матриц равна &amp;lt;math&amp;gt;2n/3&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вопрос первостепенной важности на последующем этапе реализации - это [[глоссарий#Устойчивость|&#039;&#039;устойчивость&#039;&#039;]] алгоритма. Все, что касается различных сторон этого понятия, в частности, оценки устойчивости, должно быть описано в данном разделе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Сбалансированность&#039;&#039; вычислительного процесса можно рассматривать с разных сторон. Здесь и сбалансированность типов операций, в частности, арифметических операций между собой (сложение, умножение, деление) или же арифметических операций по отношению к операциям обращения к памяти (чтение/запись). Здесь и сбалансированность операций между параллельными ветвями алгоритма. С одной стороны, балансировка нагрузки является необходимым условием эффективной реализации алгоритма. Вместе с этим, это очень непростая задача, и в описании должно быть отмечено явно, насколько алгоритм обладает этой особенностью. Если обеспечение сбалансированности не очевидно, желательно описать возможные пути решения этой задачи.&lt;br /&gt;
&lt;br /&gt;
На практике важна [[глоссарий#Детерминированность|&#039;&#039;детерминированность алгоритмов&#039;&#039;]], под которой будем понимать постоянство структуры вычислительного процесса. С этой точки зрения, классическое умножение плотных матриц является детерминированным алгоритмом, поскольку его структура при фиксированном размере матриц никак не зависит от элементов входных матриц. Умножение разреженных матриц, когда матрица хранятся в одном из специальных форматов, свойством детерминированности уже не обладает: его свойства, например, степень локальности данных зависит от структуры разреженности входных матриц. Итерационный алгоритм с выходом по точности также не является детерминированным: число итераций, а значит и число операций, меняется в зависимости от входных данных. В этом же ряду стоит использование датчиков случайных чисел, меняющих вычислительный процесс для различных запусков программы. Причина выделения свойства детерминированности понятна: работать с детерминированным алгоритмом проще, поскольку один раз найденная структура и будет определять качество его реализации. Если детерминированность нарушается, то это должно быть здесь описано вместе с описанием того, как недетерминированность влияет на структуру вычислительного процесса.&lt;br /&gt;
&lt;br /&gt;
Серьезной причиной недетерминированности работы параллельных программ является изменение порядка выполнения ассоциативных операций. Типичный пример - это использование глобальных MPI-операций на множестве параллельных процессов, например, суммирование элементов распределенного массива. Система времени исполнения MPI сама выбирает порядок выполнения операций, предполагая выполнение свойства ассоциативности, из-за чего ошибки округления меняются от запуска программы к запуску, внося изменения в конечный результат ее работы. Это очень серьезная проблема, которая сегодня встречается часто на системах с массовым параллелизмом и определяет отсутствие повторяемости результатов работы параллельных программ. Данная особенность характерна для [[#ЧАСТЬ. Программная реализация алгоритмов|второй части AlgoWiki]], посвященной реализации алгоритмов, но вопрос очень важный, и соответствующие соображения, по возможности, должны быть отмечены и здесь.&lt;br /&gt;
&lt;br /&gt;
Заметим, что, в некоторых случаях, недетерминированность в структуре алгоритмов можно &amp;quot;убрать&amp;quot; введением соответствующих макроопераций, после чего структура становится не только детерминированной, но и более понятной для восприятия. Подобное действие также следует отразить в данном разделе.&lt;br /&gt;
&lt;br /&gt;
[[глоссарий#Степень исхода|&#039;&#039;Степень исхода вершины информационного графа&#039;&#039;]] показывает, в скольких операциях ее результат будет использоваться в качестве аргумента. Если степень исхода вершины велика, то на этапе реализации алгоритма нужно позаботиться об эффективном доступе к результату ее работы. В этом смысле, особый интерес представляют рассылки данных, когда результат выполнения одной операции используется во многих других вершинах графа, причем число таких вершин растет с увеличением значения внешних переменных. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&amp;quot;Длинные&amp;quot; дуги в информационном графе&#039;&#039; &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt; говорят о потенциальных сложностях с размещением данных в иерархии памяти компьютера на этапе выполнения программы. С одной стороны, длина дуги зависит от выбора конкретной системы координат, в которой расположены вершины графа, а потому в другой системе координат они попросту могут исчезнуть (но не появится ли одновременно других длинных дуг?). А с другой стороны, вне зависимости от системы координат их присутствие может быть сигналом о необходимости длительного хранения данных на определенном уровне иерархии, что накладывает дополнительные ограничения на эффективность реализации алгоритма. Одной из причин возникновения длинных дуг являются рассылки скалярных величин по всем итерациям какого-либо цикла: в таком виде длинные дуги не вызывают каких-либо серьезных проблем на практике. &lt;br /&gt;
&lt;br /&gt;
Для проектирования специализированных процессоров или реализации алгоритма на ПЛИС представляют интерес &#039;&#039;компактные укладки информационного графа&#039;&#039; &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt;, которые также имеет смысл привести в данном разделе.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
Вторая часть описания алгоритмов в рамках AlgoWiki рассматривает все составные части процесса их реализации. Рассматривается как последовательная реализация алгоритма, так и параллельная. Описывается взаимосвязь свойств программ, реализующих алгоритм, и особенностей архитектуры компьютера, на которой они выполняются. Исследуется работа с памятью, локальность данных и вычислений, описывается масштабируемость и эффективность параллельных программ, производительность компьютеров, достигаемая на данной программе. Обсуждаются особенности реализации для разных классов архитектур компьютеров, приводятся ссылки на реализации в существующих библиотеках.&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
Здесь описываются особенности и варианты реализации алгоритма в виде последовательной программы, которые влияют на [[глоссарий#Эффективность реализации|&#039;&#039;эффективность ее выполнения&#039;&#039;]]. В частности, в данном разделе имеет смысл &#039;&#039;сказать о существовании блочных вариантов реализации алгоритма&#039;&#039;, дополнительно описав потенциальные преимущества или недостатки, сопровождающие такую реализацию. Важный вопрос - это &#039;&#039;возможные варианты организации работы с данными&#039;&#039;, варианты структур данных, наборов временных массивов и другие подобные вопросы. Для различных вариантов реализации следует оценить доступный ресурс параллелизма и объем требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
Важным нюансом является &#039;&#039;описание необходимой разрядности выполнения операций алгоритма&#039;&#039; (точности). На практике часто нет никакой необходимости выполнять все арифметические операции над вещественными числами с двойной точностью, т.к. это не влияет ни на устойчивость алгоритма, ни на точность получаемого результата. В таком случае, если значительную часть операций можно выполнять над типом float, и лишь в некоторых фрагментах необходим переход к типу double, это обязательно нужно отметить. Это прямое указание не только на правильную реализацию с точки зрения устойчивости по отношению к ошибкам округления, но и на более эффективную.&lt;br /&gt;
&lt;br /&gt;
Опираясь на информацию из [[#Описание ресурса параллелизма алгоритма|п.1.8]] (описание ресурса параллелизма алгоритма), при описании последовательной версии стоит сказать про возможности [[глоссарий#Эквивалентное преобразование|&#039;&#039;эквивалентного преобразования программ&#039;&#039;]], реализующих данных алгоритм. В дальнейшем, это даст возможность простого использования доступного параллелизма или же просто покажет, как использовать присущий алгоритму параллелизм на практике. Например, параллелизм на уровне итераций самого внутреннего цикла обычно используется для векторизации. Однако, в некоторых случаях этот параллелизм можно поднять &amp;quot;вверх&amp;quot; по структуре вложенности объемлющих циклов, что делает возможной и эффективную реализацию данного алгоритма на многоядерных SMP-компьютерах.&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;
* возможные способы распределения данных; &lt;br /&gt;
* оценку количества операций, объёма и числа пересылок данных (как общего числа, так и в пересчёте на каждый параллельный процесс); &lt;br /&gt;
&lt;br /&gt;
и другие.&lt;br /&gt;
&lt;br /&gt;
В этом же разделе должны быть даны рекомендации или сделаны комментарии относительно реализации алгоритма с помощью различных технологий параллельного программирования: MPI, OpenMP, CUDA или использования директив векторизации.&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;
На практике это сделать можно по-разному: либо все свести в один текущий раздел, либо же соответствующие факты сразу включать в предшествующие разделы, где они обсуждаются и необходимы по смыслу. В некоторых случаях, имеет смысл делать отдельные варианты всей [[#ЧАСТЬ. Программная реализация алгоритмов|части II]] AlgoWiki применительно к отдельным классам архитектур, оставляя общей машинно-независимую [[#ЧАСТЬ. Свойства и структура алгоритмов|часть I]]. В любом случае, важно указать и позитивные, и негативные факты по отношению к конкретным классам. Можно говорить о возможных вариантах оптимизации или даже о &amp;quot;трюках&amp;quot; в написании программ, ориентированных на целевые классы архитектур.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2&amp;diff=29627</id>
		<title>Структура описания свойств алгоритмов</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2&amp;diff=29627"/>
		<updated>2024-12-04T10:28:12Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Данный документ содержит описание схемы, по которой предлагается описывать свойства и структуру каждого алгоритма. Описание состоит из двух частей. В [[#ЧАСТЬ. Свойства и структура алгоритмов|первой части]] описываются собственно алгоритмы и их свойства, а [[#ЧАСТЬ. Программная реализация алгоритмов|вторая]] посвящена описанию особенностей их программной реализации с учетом конкретных программно-аппаратных платформ. Такое деление на части сделано для того, чтобы машинно-независимые свойства алгоритмов, которые определяют качество их реализации на параллельных вычислительных системах, были бы выделены и описаны отдельно от множества вопросов, связанных с последующими этапами программирования алгоритмов и исполнения результирующих программ. &lt;br /&gt;
&lt;br /&gt;
Общая схема описания алгоритмов имеет следующий вид:&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
Свойства алгоритмов никак не зависят от вычислительных систем, и с этой точки зрения данная часть AlgoWiki имеет безусловную собственную ценность. Описание алгоритма делается один раз, после чего многократно используется для его реализации в различных программно-аппаратных средах. Несмотря на то, что в данной части мы рассматриваем лишь машинно-независимые свойства алгоритмов, соображения, важные на этапе реализации, или же ссылки на соответствующие пункты [[#ЧАСТЬ. Программная реализация алгоритмов|части II AlgoWiki]], здесь также вполне уместны.&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;
В описываемом алгоритме выделяется и описывается [[глоссарий#Вычислительное ядро|&#039;&#039;вычислительное ядро&#039;&#039;]], т.е. та часть алгоритма, на которую приходится основное время работы алгоритма. Если в алгоритме несколько вычислительных ядер, то отдельно описывается каждое ядро. Описание может быть сделано в достаточно произвольной форме: словесной или с использованием языка математических формул. Вычислительное ядро может полностью совпадать с описываемым алгоритмом.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Если алгоритм использует в качестве составных частей другие алгоритмы, то это указывается в данном разделе. Если в дальнейшем имеет смысл описывать алгоритм не в максимально детализированном виде (т.е. на уровне арифметических операций), а давать только его макроструктуру, то здесь описывается структура и состав макроопераций. Если в других разделах описания данного алгоритма в рамках AlgoWiki используются введенные здесь макрооперации, то здесь даются пояснения, необходимые для однозначной интерпретации материала. Типичные варианты макроопераций, часто встречающиеся на практике: нахождение суммы элементов вектора, скалярное произведение векторов, умножение  матрицы на вектор, решение системы линейных уравнений малого порядка, сортировка, вычисление значения функции в некоторой точке, поиск минимального значения в массиве, транспонирование матрицы, вычисление обратной матрицы и многие другие.&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;
&lt;br /&gt;
Описание схемы реализации вполне может содержать и словесные пояснения, отражающие какие-либо тонкие нюансы самого алгоритма или его реализации. Уже в данном разделе можно сказать про возможный компромисс между объемом требуемой оперативной памяти и временем работы алгоритма, между используемыми структурами данных и степенью доступного параллелизма. В частности, часто возникает ситуация, когда можно ввести дополнительные временные массивы или же отказаться от использования специальных компактных схем хранения данных, увеличивая степень доступного параллелизма.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
В данном разделе описания свойств алгоритма приводится оценка его [[глоссарий#Последовательная сложность|&#039;&#039;последовательной сложности&#039;&#039;]], т.е. числа операций, которые нужно выполнить при последовательном исполнении алгоритма (в соответствии с [[#Описание схемы реализации последовательного алгоритма|п.1.5]]). Для разных алгоритмов понятие операции, в терминах которой оценивается его сложность, может существенно различаться. Это могут быть операции для работы с вещественными числами, целыми числами, поразрядные операции, обращения в память, обновления элементов массива, элементарные функции, макрооперации и другие. В LU-разложении преобладают арифметические операции над вещественными числами, а для транспонирования матриц важны лишь обращения к памяти: это и должно найти отражение в описании.&lt;br /&gt;
&lt;br /&gt;
Если выбор конкретного типа операций для оценки сложности алгоритма не очевиден, то нужно привести обоснование возможных вариантов. В некоторых случаях можно приводить оценку не всего алгоритма, а лишь его вычислительного ядра: в таком случае это нужно отметить, сославшись [[#Общее описание алгоритма|на п.1.1]]. &lt;br /&gt;
&lt;br /&gt;
Например, сложность алгоритма суммирования элементов вектора сдваиванием равна &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;. Сложность быстрого преобразования Фурье (базовый алгоритм Кули-Тьюки) для векторов с длиной, равной степени двойки – &amp;lt;math&amp;gt;n\log_2n&amp;lt;/math&amp;gt; операций комплексного сложения и &amp;lt;math&amp;gt;(n\log_2n)/2&amp;lt;/math&amp;gt; операций комплексного умножения. Сложность базового алгоритма разложения Холецкого (точечный вариант для плотной симметричной и положительно-определенной матрицы) это &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вычислений квадратного корня, &amp;lt;math&amp;gt;n(n-1)/2&amp;lt;/math&amp;gt; операций деления, по &amp;lt;math&amp;gt;(n^3-n)/6&amp;lt;/math&amp;gt; операций умножения и сложения (вычитания).&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Это очень важный раздел описания. Именно здесь можно показать (увидеть) как устроена параллельная структура алгоритма, для чего приводится описание и изображение его информационного графа ([[глоссарий#Граф алгоритма|&#039;&#039;графа алгоритма&#039;&#039;]] &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot;&amp;gt;Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. - СПб.: БХВ-Петербург, 2002. - 608 с. &amp;lt;/ref&amp;gt;). Для рисунков с изображением графа будут составлены рекомендации по их формированию, чтобы все информационные графы, внесенные в энциклопедию, можно было бы воспринимать и интерпретировать одинаково. Дополнительно можно привести полное параметрическое  описание графа в терминах покрывающих функций &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Интересных вариантов для отражения информационной структуры алгоритмов много. Для каких-то алгоритмов нужно показать максимально подробную структуру, а иногда важнее макроструктура. Много информации несут разного рода проекции информационного графа, выделяя его регулярные составляющие и одновременно скрывая несущественные детали. Иногда оказывается полезным показать последовательность в изменении графа при изменении значений внешних переменных  (например, размеров матриц): мы часто ожидаем &amp;quot;подобное&amp;quot; изменение информационного графа, но это изменение не всегда очевидно на практике.  &lt;br /&gt;
&lt;br /&gt;
В целом, задача изображения графа алгоритма весьма нетривиальна. Начнем с того, что это потенциально бесконечный граф, число вершин и дуг которого определяется значениями внешних переменных, а они могут быть весьма и весьма велики. В такой ситуации, как правило, спасают упомянутые выше соображения подобия, делающие графы для разных значений внешних переменных &amp;quot;похожими&amp;quot;: почти всегда достаточно привести лишь один граф небольшого размера, добавив, что графы для остальных значений будут устроены &amp;quot;точно также&amp;quot;. На практике, увы, не всегда все так просто, и здесь нужно быть аккуратным.&lt;br /&gt;
&lt;br /&gt;
Далее, граф алгоритма - это потенциально многомерный объект. Наиболее естественная система координат для размещения вершин и дуг информационного графа опирается на структуру вложенности циклов в реализации алгоритма. Если глубина вложенности циклов не превышает трех, то и граф размещается в привычном трехмерном пространстве, однако для более сложных циклических конструкций с глубиной вложенности 4 и больше необходимы специальные методы представления и изображения графов. &lt;br /&gt;
&lt;br /&gt;
В данном разделе AlgoWiki могут использоваться многие интересные возможности, которые еще подлежат обсуждению: возможность повернуть граф при его отображении на экране компьютера для выбора наиболее удобного угла обзора, разметка вершин по типу соответствующим им операций, отражение [[глоссарий#Ярусно-параллельная форма графа алгоритма|&#039;&#039;ярусно-параллельной формы графа&#039;&#039;]] и другие. Но в любом случае нужно не забывать главную задачу данного раздела - показать информационную структуру алгоритма так, чтобы стали понятны все его ключевые особенности, особенности параллельной структуры, особенности множеств дуг, участки регулярности и, напротив, участки с недерминированной структурой, зависящей от входных данных. &lt;br /&gt;
&lt;br /&gt;
На рис.1 показана информационная структура алгоритма умножения матриц, на рис.2 - информационная структура одного из вариантов алгоритма решения систем линейных алгебраических уравнений с блочно-двухдиагональной матрицей.&lt;br /&gt;
&lt;br /&gt;
[[file:Fig1.svg|thumb|center|300px|Рис.1. Информационная структура алгоритма умножения матриц]]&lt;br /&gt;
[[file:Fig2.svg|thumb|center|300px|Рис.2. Информационная структура одного из вариантов алгоритма решения систем линейных алгебраических уравнений с блочно-двухдиагональной матрицей]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Здесь приводится оценка [[глоссарий#Параллельная сложность|&#039;&#039;параллельной сложности&#039;&#039;]] алгоритма: числа шагов, за которое можно выполнить данный алгоритм в предположении доступности неограниченного числа необходимых процессоров (функциональных устройств, вычислительных узлов, ядер и т.п.). Параллельная сложность алгоритма понимается как высота канонической ярусно-параллельной формы &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt;. Необходимо указать, в терминах каких операций дается оценка. Необходимо описать сбалансированность параллельных шагов по числу и типу операций, что определяется шириной ярусов канонической ярусно-параллельной формы и составом операций на ярусах. &lt;br /&gt;
&lt;br /&gt;
Параллелизм в алгоритме часто имеет естественную иерархическую структуру. Этот факт очень полезен на практике, и его необходимо отразить в описании. Как правило, подобная иерархическая структура параллелизма хорошо отражается в последовательной реализации алгоритма через циклический профиль результирующей программы (конечно же, с учетом графа вызовов), поэтому циклический профиль ([[#Описание схемы реализации последовательного алгоритма|п.1.5]]) вполне  может быть использован и для отражения ресурса параллелизма.&lt;br /&gt;
&lt;br /&gt;
Для описания ресурса параллелизма алгоритма (ресурса параллелизма информационного графа) необходимо указать ключевые параллельные ветви в терминах [[глоссарий#Конечный параллелизм|&#039;&#039;конечного&#039;&#039;]] и [[глоссарий#Массовый параллелизм|&#039;&#039;массового&#039;&#039;]] параллелизма. Далеко не всегда ресурс параллелизма выражается просто, например, через [[глоссарий#Кооодинатный параллелизм|&#039;&#039;координатный параллелизм&#039;&#039;]] или, что то же самое, через независимость итераций некоторых циклов (да-да-да, циклы - это понятие, возникающее лишь на этапе реализации, но здесь все так связано… В данном случае, координатный параллелизм означает, что информационно независимые вершины лежат на гиперплоскостях, перпендикулярных одной из координатных осей). С этой точки зрения, не менее важен и ресурс [[глоссарий#Скошенный параллелизм|&#039;&#039;скошенного параллелизма&#039;&#039;]]. В отличие от координатного параллелизма, скошенный параллелизм намного сложнее использовать на практике, но знать о нем необходимо, поскольку иногда других вариантов и не остается: нужно оценить потенциал алгоритма, и лишь после этого, взвесив все альтернативы, принимать решение о конкретной параллельной реализации. Хорошей иллюстрацией может служить алгоритм, структура которого показана на рис.2: координатного параллелизма нет, но есть параллелизм скошенный, использование которого снижает сложность алгоритма с &amp;lt;math&amp;gt;n\times m&amp;lt;/math&amp;gt; в последовательном случае до &amp;lt;math&amp;gt;(n+m-1)&amp;lt;/math&amp;gt; в параллельном варианте.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим алгоритмы, последовательная сложность которых уже оценивалась в [[#Последовательная сложность алгоритма|п.1.6]]. Параллельная сложность алгоритма суммирования элементов вектора сдваиванием равна &amp;lt;math&amp;gt;\log_2n&amp;lt;/math&amp;gt;, причем число операций на каждом ярусе убывает с &amp;lt;math&amp;gt;n/2&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;. Параллельная сложность быстрого преобразования Фурье (базовый алгоритм Кули-Тьюки) для векторов с длиной, равной степени двойки - &amp;lt;math&amp;gt;\log_2n&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;(n-1)&amp;lt;/math&amp;gt; шагов для операций умножения и сложения.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
В данном разделе необходимо описать объем, структуру, особенности и свойства входных и выходных данных алгоритма: векторы, матрицы, скаляры, множества, плотные или разреженные структуры данных, их объем. Полезны предположения относительно диапазона значений или структуры, например, диагональное преобладание в структуре входных матриц, соотношение между размером матриц по отдельным размерностям, большое число матриц очень малой размерности, близость каких-то значений к машинному нулю, характер разреженности матриц и другие.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Описываются прочие свойства алгоритма, на которые имеет смысл обратить внимание на этапе реализации. Как и ранее, никакой привязки к конкретной программно-аппаратной платформе не предполагается, однако вопросы реализации в проекте AlgoWiki всегда превалируют, и необходимость обсуждения каких-либо свойств алгоритмов определяется именно этим.&lt;br /&gt;
&lt;br /&gt;
Весьма полезным является &#039;&#039;соотношение последовательной и параллельной сложности&#039;&#039; алгоритма. Оба понятия мы рассматривали ранее, но здесь делается акцент на том выигрыше, который теоретически может дать параллельная реализация алгоритма. Не менее важно описать и те сложности, которые могут возникнуть в процессе получения параллельной версии алгоритма. &lt;br /&gt;
&lt;br /&gt;
[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]] алгоритма равна отношению числа операций к суммарному объему входных и выходных данных. Она показывает, сколько операций приходится на единицу переданных данных. Несмотря на простоту данного понятия, это значение исключительно полезно на практике: чем выше  вычислительная мощность, тем меньше накладных расходов вызывает перемещение данных для их обработки, например, на сопроцессоре, ускорителе или другом узле кластера. Например, вычислительная мощность скалярного произведения двух векторов равна всего лишь &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;, а вычислительная мощность алгоритма умножения двух квадратных матриц равна &amp;lt;math&amp;gt;2n/3&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вопрос первостепенной важности на последующем этапе реализации - это [[глоссарий#Устойчивость|&#039;&#039;устойчивость&#039;&#039;]] алгоритма. Все, что касается различных сторон этого понятия, в частности, оценки устойчивости, должно быть описано в данном разделе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Сбалансированность&#039;&#039; вычислительного процесса можно рассматривать с разных сторон. Здесь и сбалансированность типов операций, в частности, арифметических операций между собой (сложение, умножение, деление) или же арифметических операций по отношению к операциям обращения к памяти (чтение/запись). Здесь и сбалансированность операций между параллельными ветвями алгоритма. С одной стороны, балансировка нагрузки является необходимым условием эффективной реализации алгоритма. Вместе с этим, это очень непростая задача, и в описании должно быть отмечено явно, насколько алгоритм обладает этой особенностью. Если обеспечение сбалансированности не очевидно, желательно описать возможные пути решения этой задачи.&lt;br /&gt;
&lt;br /&gt;
На практике важна [[глоссарий#Детерминированность|&#039;&#039;детерминированность алгоритмов&#039;&#039;]], под которой будем понимать постоянство структуры вычислительного процесса. С этой точки зрения, классическое умножение плотных матриц является детерминированным алгоритмом, поскольку его структура при фиксированном размере матриц никак не зависит от элементов входных матриц. Умножение разреженных матриц, когда матрица хранятся в одном из специальных форматов, свойством детерминированности уже не обладает: его свойства, например, степень локальности данных зависит от структуры разреженности входных матриц. Итерационный алгоритм с выходом по точности также не является детерминированным: число итераций, а значит и число операций, меняется в зависимости от входных данных. В этом же ряду стоит использование датчиков случайных чисел, меняющих вычислительный процесс для различных запусков программы. Причина выделения свойства детерминированности понятна: работать с детерминированным алгоритмом проще, поскольку один раз найденная структура и будет определять качество его реализации. Если детерминированность нарушается, то это должно быть здесь описано вместе с описанием того, как недетерминированность влияет на структуру вычислительного процесса.&lt;br /&gt;
&lt;br /&gt;
Серьезной причиной недетерминированности работы параллельных программ является изменение порядка выполнения ассоциативных операций. Типичный пример - это использование глобальных MPI-операций на множестве параллельных процессов, например, суммирование элементов распределенного массива. Система времени исполнения MPI сама выбирает порядок выполнения операций, предполагая выполнение свойства ассоциативности, из-за чего ошибки округления меняются от запуска программы к запуску, внося изменения в конечный результат ее работы. Это очень серьезная проблема, которая сегодня встречается часто на системах с массовым параллелизмом и определяет отсутствие повторяемости результатов работы параллельных программ. Данная особенность характерна для [[#ЧАСТЬ. Программная реализация алгоритмов|второй части AlgoWiki]], посвященной реализации алгоритмов, но вопрос очень важный, и соответствующие соображения, по возможности, должны быть отмечены и здесь.&lt;br /&gt;
&lt;br /&gt;
Заметим, что, в некоторых случаях, недетерминированность в структуре алгоритмов можно &amp;quot;убрать&amp;quot; введением соответствующих макроопераций, после чего структура становится не только детерминированной, но и более понятной для восприятия. Подобное действие также следует отразить в данном разделе.&lt;br /&gt;
&lt;br /&gt;
[[глоссарий#Степень исхода|&#039;&#039;Степень исхода вершины информационного графа&#039;&#039;]] показывает, в скольких операциях ее результат будет использоваться в качестве аргумента. Если степень исхода вершины велика, то на этапе реализации алгоритма нужно позаботиться об эффективном доступе к результату ее работы. В этом смысле, особый интерес представляют рассылки данных, когда результат выполнения одной операции используется во многих других вершинах графа, причем число таких вершин растет с увеличением значения внешних переменных. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&amp;quot;Длинные&amp;quot; дуги в информационном графе&#039;&#039; &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt; говорят о потенциальных сложностях с размещением данных в иерархии памяти компьютера на этапе выполнения программы. С одной стороны, длина дуги зависит от выбора конкретной системы координат, в которой расположены вершины графа, а потому в другой системе координат они попросту могут исчезнуть (но не появится ли одновременно других длинных дуг?). А с другой стороны, вне зависимости от системы координат их присутствие может быть сигналом о необходимости длительного хранения данных на определенном уровне иерархии, что накладывает дополнительные ограничения на эффективность реализации алгоритма. Одной из причин возникновения длинных дуг являются рассылки скалярных величин по всем итерациям какого-либо цикла: в таком виде длинные дуги не вызывают каких-либо серьезных проблем на практике. &lt;br /&gt;
&lt;br /&gt;
Для проектирования специализированных процессоров или реализации алгоритма на ПЛИС представляют интерес &#039;&#039;компактные укладки информационного графа&#039;&#039; &amp;lt;ref name=&amp;quot;VVVVVV&amp;quot; /&amp;gt;, которые также имеет смысл привести в данном разделе.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
Вторая часть описания алгоритмов в рамках AlgoWiki рассматривает все составные части процесса их реализации. Рассматривается как последовательная реализация алгоритма, так и параллельная. Описывается взаимосвязь свойств программ, реализующих алгоритм, и особенностей архитектуры компьютера, на которой они выполняются. Исследуется работа с памятью, локальность данных и вычислений, описывается масштабируемость и эффективность параллельных программ, производительность компьютеров, достигаемая на данной программе. Обсуждаются особенности реализации для разных классов архитектур компьютеров, приводятся ссылки на реализации в существующих библиотеках.&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
Здесь описываются особенности и варианты реализации алгоритма в виде последовательной программы, которые влияют на [[глоссарий#Эффективность реализации|&#039;&#039;эффективность ее выполнения&#039;&#039;]]. В частности, в данном разделе имеет смысл &#039;&#039;сказать о существовании блочных вариантов реализации алгоритма&#039;&#039;, дополнительно описав потенциальные преимущества или недостатки, сопровождающие такую реализацию. Важный вопрос - это &#039;&#039;возможные варианты организации работы с данными&#039;&#039;, варианты структур данных, наборов временных массивов и другие подобные вопросы. Для различных вариантов реализации следует оценить доступный ресурс параллелизма и объем требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
Важным нюансом является &#039;&#039;описание необходимой разрядности выполнения операций алгоритма&#039;&#039; (точности). На практике часто нет никакой необходимости выполнять все арифметические операции над вещественными числами с двойной точностью, т.к. это не влияет ни на устойчивость алгоритма, ни на точность получаемого результата. В таком случае, если значительную часть операций можно выполнять над типом float, и лишь в некоторых фрагментах необходим переход к типу double, это обязательно нужно отметить. Это прямое указание не только на правильную реализацию с точки зрения устойчивости по отношению к ошибкам округления, но и на более эффективную.&lt;br /&gt;
&lt;br /&gt;
Опираясь на информацию из [[#Описание ресурса параллелизма алгоритма|п.1.8]] (описание ресурса параллелизма алгоритма), при описании последовательной версии стоит сказать про возможности [[глоссарий#Эквивалентное преобразование|&#039;&#039;эквивалентного преобразования программ&#039;&#039;]], реализующих данных алгоритм. В дальнейшем, это даст возможность простого использования доступного параллелизма или же просто покажет, как использовать присущий алгоритму параллелизм на практике. Например, параллелизм на уровне итераций самого внутреннего цикла обычно используется для векторизации. Однако, в некоторых случаях этот параллелизм можно поднять &amp;quot;вверх&amp;quot; по структуре вложенности объемлющих циклов, что делает возможной и эффективную реализацию данного алгоритма на многоядерных SMP-компьютерах.&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;
В данный раздел должны быть включены рекомендации по реализации алгоритма для разных классов архитектур. Если архитектура какого-либо компьютера или платформы обладает специфическими особенностями, влияющими на эффективность реализации, то это здесь нужно отметить.&lt;br /&gt;
&lt;br /&gt;
На практике это сделать можно по-разному: либо все свести в один текущий раздел, либо же соответствующие факты сразу включать в предшествующие разделы, где они обсуждаются и необходимы по смыслу. В некоторых случаях, имеет смысл делать отдельные варианты всей [[#ЧАСТЬ. Программная реализация алгоритмов|части II]] AlgoWiki применительно к отдельным классам архитектур, оставляя общей машинно-независимую [[#ЧАСТЬ. Свойства и структура алгоритмов|часть I]]. В любом случае, важно указать и позитивные, и негативные факты по отношению к конкретным классам. Можно говорить о возможных вариантах оптимизации или даже о &amp;quot;трюках&amp;quot; в написании программ, ориентированных на целевые классы архитектур.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29626</id>
		<title>Структура описания свойств программных реализаций</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29626"/>
		<updated>2024-12-04T10:23:50Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
Вопросы локальности данных и вычислений не часто изучаются на практике, но именно локальность определяет эффективность выполнения программ на современных вычислительных платформах &amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вад.В. Спасительная локальность суперкомпьютеров //Открытые системы. - 2013. - № 9. - С. 12-15.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин Вад.В., Швец П. Метод покрытий для оценки локальности использования данных в программах // Вестник УГАТУ. — 2014. — Т. 18, № 1(62). — С. 224–229.&amp;lt;/ref&amp;gt;. В данном разделе приводятся оценки степени [[глоссарий#Локальность использования данных|&#039;&#039;локальности данных&#039;&#039;]] и [[глоссарий#Локальность вычислений|вычислений]] в программе, причем рассматривается как [[глоссарий#Временная локальность|&#039;&#039;временна́я&#039;&#039;]], так и [[глоссарий#Пространственная локальность|&#039;&#039;пространственная&#039;&#039;]] локальность. Отмечаются позитивные и негативные факты, связанные с локальностью, какие ситуации и при каких условиях могут возникать. Исследуется, как меняется локальность при переходе от последовательной реализации к параллельной. Выделяются ключевые шаблоны взаимодействия программы, реализующей описываемый алгоритм, с памятью. Отмечается возможная взаимосвязь между используемыми конструкциями языков программирования и степенью локальности, которыми обладают результирующие программы. &lt;br /&gt;
&lt;br /&gt;
Отдельно приводятся профили взаимодействия с памятью для вычислительных ядер и ключевых фрагментов. Если из-за большого числа обращений по общему профилю сложно понять реальную специфику взаимодействия программ с памятью, то проводится последовательная детализация и приводится серия профилей более мелкого масштаба. &lt;br /&gt;
&lt;br /&gt;
На рис.3 и рис.4 показаны профили обращения в память для программ, реализующих разложение Холецкого и быстрое преобразование Фурье, по которым хорошо видна разница свойств локальности у данных алгоритмов.&lt;br /&gt;
&lt;br /&gt;
[[file:Cholesky_locality1.jpg|thumb|center|700px|Рис.3 Реализация метода Холецкого. Общий профиль обращений в память]]&lt;br /&gt;
[[file:fft 1.PNG|thumb|center|700px|Рис.4 Нерекурсивная реализация БПФ для степеней двойки. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
Задача данного раздела - показать пределы [[глоссарий#Масштабируемость|&#039;&#039;масштабируемости&#039;&#039;]] алгоритма на различных платформах. Очень важный раздел. Нужно выделить, описать и оценить влияние точек барьерной синхронизации, глобальных операций, операций сборки/разборки данных, привести оценки или провести исследование [[глоссарий#Сильная масштабируемость|&#039;&#039;сильной&#039;&#039;]] и [[глоссарий#Слабая масштабируемость|&#039;&#039;слабой&#039;&#039;]] масштабируемости алгоритма и его реализаций.&lt;br /&gt;
&lt;br /&gt;
Масштабируемость алгоритма определяет свойства самого алгоритма безотносительно конкретных особенностей используемого компьютера. Она показывает, насколько параллельные свойства алгоритма позволяют использовать возможности растущего числа процессорных элементов. Масштабируемость параллельных программ определяется как относительно конкретного компьютера, так и относительно используемой технологии программирования, и в этом случае она показывает, насколько может вырасти реальная производительность данного компьютера на данной программе, записанной с помощью данной технологии программирования, при использовании бóльших вычислительных ресурсов (ядер, процессоров, вычислительных узлов).&lt;br /&gt;
&lt;br /&gt;
Ключевой момент данного раздела заключается в том, чтобы показать &#039;&#039;реальные параметры масштабируемости программы&#039;&#039; для данного алгоритма на различных вычислительных платформах в зависимости от числа процессоров и размера задачи &amp;lt;ref&amp;gt;Антонов А.С., Теплов А.М. О практической сложности понятия масштабируемости параллельных программ// Высокопроизводительные параллельные вычисления на кластерных системах (HPC 2014): Материалы XIV Международной конференции -Пермь: Издательство ПНИПУ, 2014. С. 20-27.&amp;lt;/ref&amp;gt;. При этом важно подобрать такое соотношение между числом процессоров и размером задачи, чтобы отразить все характерные точки в поведении параллельной программы, в частности, достижение максимальной производительности, а также тонкие эффекты, возникающие, например, из-за блочной структуры алгоритма или иерархии памяти.&lt;br /&gt;
&lt;br /&gt;
На рис.5. показана масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи. На графике хорошо видны области с большей производительностью, отвечающие уровням кэш-памяти.&lt;br /&gt;
[[file:Масштабируемость перемножения матриц производительность.png|thumb|center|700px|Рис.5 Масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
Это объемный раздел AlgoWiki, поскольку оценка эффективности реализации алгоритма требует комплексного подхода &amp;lt;ref&amp;gt;Никитенко Д.А. Комплексный анализ производительности суперкомпьютерных систем, основанный на данных системного мониторинга // Вычислительные методы и программирование. 2014. 15. 85–97.&amp;lt;/ref&amp;gt;, предполагающего аккуратный анализ всех этапов от архитектуры компьютера до самого алгоритма. Основная задача данного раздела заключается в том, чтобы оценить степень эффективности параллельных программ, реализующих данный алгоритм на различных платформах, в зависимости от числа процессоров и размера задачи. Эффективность в данном разделе понимается широко: это и [[глоссарий#Эффективность распараллеливания|&#039;&#039;эффективность распараллеливания&#039;&#039;]] программы, это и [[глоссарий#Эффективность реализации|&#039;&#039;эффективность реализации&#039;&#039;]] программ по отношению к пиковым показателям работы вычислительных систем. &lt;br /&gt;
&lt;br /&gt;
Помимо собственно показателей эффективности, нужно описать и все основные причины, из-за которых эффективность работы параллельной программы на конкретной вычислительной платформе не удается сделать выше. Это не самая простая задача, поскольку на данный момент нет общепринятой методики и соответствующего инструментария, с помощью которых подобный анализ можно было бы провести. Требуется оценить и описать эффективность работы с памятью (особенности профиля взаимодействия программы с памятью), эффективность использования заложенного в алгоритм ресурса параллелизма, эффективность использования коммуникационной сети (особенности коммуникационного профиля), эффективность операций ввода/вывода и т.п. Иногда достаточно интегральных характеристик по работе программы, в некоторых случаях полезно показать данные мониторинга нижнего уровня, например, по загрузке процессора, кэш-промахам, интенсивности использования сети Infiniband и т.п. Хорошее представление о работе параллельной MPI-программы дают данные трассировки, полученные, например, с помощью системы Scalasca.&lt;br /&gt;
&lt;br /&gt;
== Результаты прогонов ==&lt;br /&gt;
&lt;br /&gt;
В данном разделе приводятся результаты прогонов данной программной реализации на различных программно-аппаратных платформах.&lt;br /&gt;
&lt;br /&gt;
Литература&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en:Description of implementation properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29625</id>
		<title>Структура описания свойств программных реализаций</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29625"/>
		<updated>2024-12-04T10:23:04Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
Вопросы локальности данных и вычислений не часто изучаются на практике, но именно локальность определяет эффективность выполнения программ на современных вычислительных платформах &amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вад.В. Спасительная локальность суперкомпьютеров //Открытые системы. - 2013. - № 9. - С. 12-15.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин Вад.В., Швец П. Метод покрытий для оценки локальности использования данных в программах // Вестник УГАТУ. — 2014. — Т. 18, № 1(62). — С. 224–229.&amp;lt;/ref&amp;gt;. В данном разделе приводятся оценки степени [[глоссарий#Локальность использования данных|&#039;&#039;локальности данных&#039;&#039;]] и [[глоссарий#Локальность вычислений|вычислений]] в программе, причем рассматривается как [[глоссарий#Временная локальность|&#039;&#039;временна́я&#039;&#039;]], так и [[глоссарий#Пространственная локальность|&#039;&#039;пространственная&#039;&#039;]] локальность. Отмечаются позитивные и негативные факты, связанные с локальностью, какие ситуации и при каких условиях могут возникать. Исследуется, как меняется локальность при переходе от последовательной реализации к параллельной. Выделяются ключевые шаблоны взаимодействия программы, реализующей описываемый алгоритм, с памятью. Отмечается возможная взаимосвязь между используемыми конструкциями языков программирования и степенью локальности, которыми обладают результирующие программы. &lt;br /&gt;
&lt;br /&gt;
Отдельно приводятся профили взаимодействия с памятью для вычислительных ядер и ключевых фрагментов. Если из-за большого числа обращений по общему профилю сложно понять реальную специфику взаимодействия программ с памятью, то проводится последовательная детализация и приводится серия профилей более мелкого масштаба. &lt;br /&gt;
&lt;br /&gt;
На рис.3 и рис.4 показаны профили обращения в память для программ, реализующих разложение Холецкого и быстрое преобразование Фурье, по которым хорошо видна разница свойств локальности у данных алгоритмов.&lt;br /&gt;
&lt;br /&gt;
[[file:Cholesky_locality1.jpg|thumb|center|700px|Рис.3 Реализация метода Холецкого. Общий профиль обращений в память]]&lt;br /&gt;
[[file:fft 1.PNG|thumb|center|700px|Рис.4 Нерекурсивная реализация БПФ для степеней двойки. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
Задача данного раздела - показать пределы [[глоссарий#Масштабируемость|&#039;&#039;масштабируемости&#039;&#039;]] алгоритма на различных платформах. Очень важный раздел. Нужно выделить, описать и оценить влияние точек барьерной синхронизации, глобальных операций, операций сборки/разборки данных, привести оценки или провести исследование [[глоссарий#Сильная масштабируемость|&#039;&#039;сильной&#039;&#039;]] и [[глоссарий#Слабая масштабируемость|&#039;&#039;слабой&#039;&#039;]] масштабируемости алгоритма и его реализаций.&lt;br /&gt;
&lt;br /&gt;
Масштабируемость алгоритма определяет свойства самого алгоритма безотносительно конкретных особенностей используемого компьютера. Она показывает, насколько параллельные свойства алгоритма позволяют использовать возможности растущего числа процессорных элементов. Масштабируемость параллельных программ определяется как относительно конкретного компьютера, так и относительно используемой технологии программирования, и в этом случае она показывает, насколько может вырасти реальная производительность данного компьютера на данной программе, записанной с помощью данной технологии программирования, при использовании бóльших вычислительных ресурсов (ядер, процессоров, вычислительных узлов).&lt;br /&gt;
&lt;br /&gt;
Ключевой момент данного раздела заключается в том, чтобы показать &#039;&#039;реальные параметры масштабируемости программы&#039;&#039; для данного алгоритма на различных вычислительных платформах в зависимости от числа процессоров и размера задачи &amp;lt;ref&amp;gt;Антонов А.С., Теплов А.М. О практической сложности понятия масштабируемости параллельных программ// Высокопроизводительные параллельные вычисления на кластерных системах (HPC 2014): Материалы XIV Международной конференции -Пермь: Издательство ПНИПУ, 2014. С. 20-27.&amp;lt;/ref&amp;gt;. При этом важно подобрать такое соотношение между числом процессоров и размером задачи, чтобы отразить все характерные точки в поведении параллельной программы, в частности, достижение максимальной производительности, а также тонкие эффекты, возникающие, например, из-за блочной структуры алгоритма или иерархии памяти.&lt;br /&gt;
&lt;br /&gt;
На рис.5. показана масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи. На графике хорошо видны области с большей производительностью, отвечающие уровням кэш-памяти.&lt;br /&gt;
[[file:Масштабируемость перемножения матриц производительность.png|thumb|center|700px|Рис.5 Масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
Это объемный раздел AlgoWiki, поскольку оценка эффективности реализации алгоритма требует комплексного подхода &amp;lt;ref&amp;gt;Никитенко Д.А. Комплексный анализ производительности суперкомпьютерных систем, основанный на данных системного мониторинга // Вычислительные методы и программирование. 2014. 15. 85–97.&amp;lt;/ref&amp;gt;, предполагающего аккуратный анализ всех этапов от архитектуры компьютера до самого алгоритма. Основная задача данного раздела заключается в том, чтобы оценить степень эффективности параллельных программ, реализующих данный алгоритм на различных платформах, в зависимости от числа процессоров и размера задачи. Эффективность в данном разделе понимается широко: это и [[глоссарий#Эффективность распараллеливания|&#039;&#039;эффективность распараллеливания&#039;&#039;]] программы, это и [[глоссарий#Эффективность реализации|&#039;&#039;эффективность реализации&#039;&#039;]] программ по отношению к пиковым показателям работы вычислительных систем. &lt;br /&gt;
&lt;br /&gt;
Помимо собственно показателей эффективности, нужно описать и все основные причины, из-за которых эффективность работы параллельной программы на конкретной вычислительной платформе не удается сделать выше. Это не самая простая задача, поскольку на данный момент нет общепринятой методики и соответствующего инструментария, с помощью которых подобный анализ можно было бы провести. Требуется оценить и описать эффективность работы с памятью (особенности профиля взаимодействия программы с памятью), эффективность использования заложенного в алгоритм ресурса параллелизма, эффективность использования коммуникационной сети (особенности коммуникационного профиля), эффективность операций ввода/вывода и т.п. Иногда достаточно интегральных характеристик по работе программы, в некоторых случаях полезно показать данные мониторинга нижнего уровня, например, по загрузке процессора, кэш-промахам, интенсивности использования сети Infiniband и т.п. Хорошее представление о работе параллельной MPI-программы дают данные трассировки, полученные, например, с помощью системы Scalasca.&lt;br /&gt;
&lt;br /&gt;
== Результаты прогонов ==&lt;br /&gt;
&lt;br /&gt;
В данном разделе приводятся результаты прогонов данной программной реализации на различных программно-аппаратных платформах.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[[en:Description of implementation properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29624</id>
		<title>Структура описания свойств программных реализаций</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29624"/>
		<updated>2024-12-04T09:55:06Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
Вопросы локальности данных и вычислений не часто изучаются на практике, но именно локальность определяет эффективность выполнения программ на современных вычислительных платформах &amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вад.В. Спасительная локальность суперкомпьютеров //Открытые системы. - 2013. - № 9. - С. 12-15.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин Вад.В., Швец П. Метод покрытий для оценки локальности использования данных в программах // Вестник УГАТУ. — 2014. — Т. 18, № 1(62). — С. 224–229.&amp;lt;/ref&amp;gt;. В данном разделе приводятся оценки степени [[глоссарий#Локальность использования данных|&#039;&#039;локальности данных&#039;&#039;]] и [[глоссарий#Локальность вычислений|вычислений]] в программе, причем рассматривается как [[глоссарий#Временная локальность|&#039;&#039;временна́я&#039;&#039;]], так и [[глоссарий#Пространственная локальность|&#039;&#039;пространственная&#039;&#039;]] локальность. Отмечаются позитивные и негативные факты, связанные с локальностью, какие ситуации и при каких условиях могут возникать. Исследуется, как меняется локальность при переходе от последовательной реализации к параллельной. Выделяются ключевые шаблоны взаимодействия программы, реализующей описываемый алгоритм, с памятью. Отмечается возможная взаимосвязь между используемыми конструкциями языков программирования и степенью локальности, которыми обладают результирующие программы. &lt;br /&gt;
&lt;br /&gt;
Отдельно приводятся профили взаимодействия с памятью для вычислительных ядер и ключевых фрагментов. Если из-за большого числа обращений по общему профилю сложно понять реальную специфику взаимодействия программ с памятью, то проводится последовательная детализация и приводится серия профилей более мелкого масштаба. &lt;br /&gt;
&lt;br /&gt;
На рис.3 и рис.4 показаны профили обращения в память для программ, реализующих разложение Холецкого и быстрое преобразование Фурье, по которым хорошо видна разница свойств локальности у данных алгоритмов.&lt;br /&gt;
&lt;br /&gt;
[[file:Cholesky_locality1.jpg|thumb|center|700px|Рис.3 Реализация метода Холецкого. Общий профиль обращений в память]]&lt;br /&gt;
[[file:fft 1.PNG|thumb|center|700px|Рис.4 Нерекурсивная реализация БПФ для степеней двойки. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
Задача данного раздела - показать пределы [[глоссарий#Масштабируемость|&#039;&#039;масштабируемости&#039;&#039;]] алгоритма на различных платформах. Очень важный раздел. Нужно выделить, описать и оценить влияние точек барьерной синхронизации, глобальных операций, операций сборки/разборки данных, привести оценки или провести исследование [[глоссарий#Сильная масштабируемость|&#039;&#039;сильной&#039;&#039;]] и [[глоссарий#Слабая масштабируемость|&#039;&#039;слабой&#039;&#039;]] масштабируемости алгоритма и его реализаций.&lt;br /&gt;
&lt;br /&gt;
Масштабируемость алгоритма определяет свойства самого алгоритма безотносительно конкретных особенностей используемого компьютера. Она показывает, насколько параллельные свойства алгоритма позволяют использовать возможности растущего числа процессорных элементов. Масштабируемость параллельных программ определяется как относительно конкретного компьютера, так и относительно используемой технологии программирования, и в этом случае она показывает, насколько может вырасти реальная производительность данного компьютера на данной программе, записанной с помощью данной технологии программирования, при использовании бóльших вычислительных ресурсов (ядер, процессоров, вычислительных узлов).&lt;br /&gt;
&lt;br /&gt;
Ключевой момент данного раздела заключается в том, чтобы показать &#039;&#039;реальные параметры масштабируемости программы&#039;&#039; для данного алгоритма на различных вычислительных платформах в зависимости от числа процессоров и размера задачи &amp;lt;ref&amp;gt;Антонов А.С., Теплов А.М. О практической сложности понятия масштабируемости параллельных программ// Высокопроизводительные параллельные вычисления на кластерных системах (HPC 2014): Материалы XIV Международной конференции -Пермь: Издательство ПНИПУ, 2014. С. 20-27.&amp;lt;/ref&amp;gt;. При этом важно подобрать такое соотношение между числом процессоров и размером задачи, чтобы отразить все характерные точки в поведении параллельной программы, в частности, достижение максимальной производительности, а также тонкие эффекты, возникающие, например, из-за блочной структуры алгоритма или иерархии памяти.&lt;br /&gt;
&lt;br /&gt;
На рис.5. показана масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи. На графике хорошо видны области с большей производительностью, отвечающие уровням кэш-памяти.&lt;br /&gt;
[[file:Масштабируемость перемножения матриц производительность.png|thumb|center|700px|Рис.5 Масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
Это объемный раздел AlgoWiki, поскольку оценка эффективности реализации алгоритма требует комплексного подхода &amp;lt;ref&amp;gt;Никитенко Д.А. Комплексный анализ производительности суперкомпьютерных систем, основанный на данных системного мониторинга // Вычислительные методы и программирование. 2014. 15. 85–97.&amp;lt;/ref&amp;gt;, предполагающего аккуратный анализ всех этапов от архитектуры компьютера до самого алгоритма. Основная задача данного раздела заключается в том, чтобы оценить степень эффективности параллельных программ, реализующих данный алгоритм на различных платформах, в зависимости от числа процессоров и размера задачи. Эффективность в данном разделе понимается широко: это и [[глоссарий#Эффективность распараллеливания|&#039;&#039;эффективность распараллеливания&#039;&#039;]] программы, это и [[глоссарий#Эффективность реализации|&#039;&#039;эффективность реализации&#039;&#039;]] программ по отношению к пиковым показателям работы вычислительных систем. &lt;br /&gt;
&lt;br /&gt;
Помимо собственно показателей эффективности, нужно описать и все основные причины, из-за которых эффективность работы параллельной программы на конкретной вычислительной платформе не удается сделать выше. Это не самая простая задача, поскольку на данный момент нет общепринятой методики и соответствующего инструментария, с помощью которых подобный анализ можно было бы провести. Требуется оценить и описать эффективность работы с памятью (особенности профиля взаимодействия программы с памятью), эффективность использования заложенного в алгоритм ресурса параллелизма, эффективность использования коммуникационной сети (особенности коммуникационного профиля), эффективность операций ввода/вывода и т.п. Иногда достаточно интегральных характеристик по работе программы, в некоторых случаях полезно показать данные мониторинга нижнего уровня, например, по загрузке процессора, кэш-промахам, интенсивности использования сети Infiniband и т.п. Хорошее представление о работе параллельной MPI-программы дают данные трассировки, полученные, например, с помощью системы Scalasca.&lt;br /&gt;
&lt;br /&gt;
== Результаты прогонов ==&lt;br /&gt;
&lt;br /&gt;
В данном разделе приводятся результаты прогонов данной программной реализации на различных программно-аппаратных платформах.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[en:Description of implementation properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29623</id>
		<title>Структура описания свойств программных реализаций</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29623"/>
		<updated>2024-12-04T09:04:31Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
Вопросы локальности данных и вычислений не часто изучаются на практике, но именно локальность определяет эффективность выполнения программ на современных вычислительных платформах &amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вад.В. Спасительная локальность суперкомпьютеров //Открытые системы. - 2013. - № 9. - С. 12-15.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин Вад.В., Швец П. Метод покрытий для оценки локальности использования данных в программах // Вестник УГАТУ. — 2014. — Т. 18, № 1(62). — С. 224–229.&amp;lt;/ref&amp;gt;. В данном разделе приводятся оценки степени [[глоссарий#Локальность использования данных|&#039;&#039;локальности данных&#039;&#039;]] и [[глоссарий#Локальность вычислений|вычислений]] в программе, причем рассматривается как [[глоссарий#Временная локальность|&#039;&#039;временна́я&#039;&#039;]], так и [[глоссарий#Пространственная локальность|&#039;&#039;пространственная&#039;&#039;]] локальность. Отмечаются позитивные и негативные факты, связанные с локальностью, какие ситуации и при каких условиях могут возникать. Исследуется, как меняется локальность при переходе от последовательной реализации к параллельной. Выделяются ключевые шаблоны взаимодействия программы, реализующей описываемый алгоритм, с памятью. Отмечается возможная взаимосвязь между используемыми конструкциями языков программирования и степенью локальности, которыми обладают результирующие программы. &lt;br /&gt;
&lt;br /&gt;
Отдельно приводятся профили взаимодействия с памятью для вычислительных ядер и ключевых фрагментов. Если из-за большого числа обращений по общему профилю сложно понять реальную специфику взаимодействия программ с памятью, то проводится последовательная детализация и приводится серия профилей более мелкого масштаба. &lt;br /&gt;
&lt;br /&gt;
На рис.3 и рис.4 показаны профили обращения в память для программ, реализующих разложение Холецкого и быстрое преобразование Фурье, по которым хорошо видна разница свойств локальности у данных алгоритмов.&lt;br /&gt;
&lt;br /&gt;
[[file:Cholesky_locality1.jpg|thumb|center|700px|Рис.3 Реализация метода Холецкого. Общий профиль обращений в память]]&lt;br /&gt;
[[file:fft 1.PNG|thumb|center|700px|Рис.4 Нерекурсивная реализация БПФ для степеней двойки. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
Задача данного раздела - показать пределы [[глоссарий#Масштабируемость|&#039;&#039;масштабируемости&#039;&#039;]] алгоритма на различных платформах. Очень важный раздел. Нужно выделить, описать и оценить влияние точек барьерной синхронизации, глобальных операций, операций сборки/разборки данных, привести оценки или провести исследование [[глоссарий#Сильная масштабируемость|&#039;&#039;сильной&#039;&#039;]] и [[глоссарий#Слабая масштабируемость|&#039;&#039;слабой&#039;&#039;]] масштабируемости алгоритма и его реализаций.&lt;br /&gt;
&lt;br /&gt;
Масштабируемость алгоритма определяет свойства самого алгоритма безотносительно конкретных особенностей используемого компьютера. Она показывает, насколько параллельные свойства алгоритма позволяют использовать возможности растущего числа процессорных элементов. Масштабируемость параллельных программ определяется как относительно конкретного компьютера, так и относительно используемой технологии программирования, и в этом случае она показывает, насколько может вырасти реальная производительность данного компьютера на данной программе, записанной с помощью данной технологии программирования, при использовании бóльших вычислительных ресурсов (ядер, процессоров, вычислительных узлов).&lt;br /&gt;
&lt;br /&gt;
Ключевой момент данного раздела заключается в том, чтобы показать &#039;&#039;реальные параметры масштабируемости программы&#039;&#039; для данного алгоритма на различных вычислительных платформах в зависимости от числа процессоров и размера задачи &amp;lt;ref&amp;gt;Антонов А.С., Теплов А.М. О практической сложности понятия масштабируемости параллельных программ// Высокопроизводительные параллельные вычисления на кластерных системах (HPC 2014): Материалы XIV Международной конференции -Пермь: Издательство ПНИПУ, 2014. С. 20-27.&amp;lt;/ref&amp;gt;. При этом важно подобрать такое соотношение между числом процессоров и размером задачи, чтобы отразить все характерные точки в поведении параллельной программы, в частности, достижение максимальной производительности, а также тонкие эффекты, возникающие, например, из-за блочной структуры алгоритма или иерархии памяти.&lt;br /&gt;
&lt;br /&gt;
На рис.5. показана масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи. На графике хорошо видны области с большей производительностью, отвечающие уровням кэш-памяти.&lt;br /&gt;
[[file:Масштабируемость перемножения матриц производительность.png|thumb|center|700px|Рис.5 Масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
Это объемный раздел AlgoWiki, поскольку оценка эффективности реализации алгоритма требует комплексного подхода &amp;lt;ref&amp;gt;Никитенко Д.А. Комплексный анализ производительности суперкомпьютерных систем, основанный на данных системного мониторинга // Вычислительные методы и программирование. 2014. 15. 85–97.&amp;lt;/ref&amp;gt;, предполагающего аккуратный анализ всех этапов от архитектуры компьютера до самого алгоритма. Основная задача данного раздела заключается в том, чтобы оценить степень эффективности параллельных программ, реализующих данный алгоритм на различных платформах, в зависимости от числа процессоров и размера задачи. Эффективность в данном разделе понимается широко: это и [[глоссарий#Эффективность распараллеливания|&#039;&#039;эффективность распараллеливания&#039;&#039;]] программы, это и [[глоссарий#Эффективность реализации|&#039;&#039;эффективность реализации&#039;&#039;]] программ по отношению к пиковым показателям работы вычислительных систем. &lt;br /&gt;
&lt;br /&gt;
Помимо собственно показателей эффективности, нужно описать и все основные причины, из-за которых эффективность работы параллельной программы на конкретной вычислительной платформе не удается сделать выше. Это не самая простая задача, поскольку на данный момент нет общепринятой методики и соответствующего инструментария, с помощью которых подобный анализ можно было бы провести. Требуется оценить и описать эффективность работы с памятью (особенности профиля взаимодействия программы с памятью), эффективность использования заложенного в алгоритм ресурса параллелизма, эффективность использования коммуникационной сети (особенности коммуникационного профиля), эффективность операций ввода/вывода и т.п. Иногда достаточно интегральных характеристик по работе программы, в некоторых случаях полезно показать данные мониторинга нижнего уровня, например, по загрузке процессора, кэш-промахам, интенсивности использования сети Infiniband и т.п. Хорошее представление о работе параллельной MPI-программы дают данные трассировки, полученные, например, с помощью системы Scalasca.&lt;br /&gt;
&lt;br /&gt;
== Результаты прогонов ==&lt;br /&gt;
&lt;br /&gt;
В данном разделе приводятся результаты прогонов данной программной реализации на различных программно-аппаратных платформах.&lt;br /&gt;
&lt;br /&gt;
[[en:Description of implementation properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29622</id>
		<title>Структура описания свойств программных реализаций</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D1%8B%D1%85_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B9&amp;diff=29622"/>
		<updated>2024-12-04T09:02:33Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «Данный документ содержит описание схемы, по которой предлагается описывать свойства и с...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
Вопросы локальности данных и вычислений не часто изучаются на практике, но именно локальность определяет эффективность выполнения программ на современных вычислительных платформах &amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вад.В. Спасительная локальность суперкомпьютеров //Открытые системы. - 2013. - № 9. - С. 12-15.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин Вад.В., Швец П. Метод покрытий для оценки локальности использования данных в программах // Вестник УГАТУ. — 2014. — Т. 18, № 1(62). — С. 224–229.&amp;lt;/ref&amp;gt;. В данном разделе приводятся оценки степени [[глоссарий#Локальность использования данных|&#039;&#039;локальности данных&#039;&#039;]] и [[глоссарий#Локальность вычислений|вычислений]] в программе, причем рассматривается как [[глоссарий#Временная локальность|&#039;&#039;временна́я&#039;&#039;]], так и [[глоссарий#Пространственная локальность|&#039;&#039;пространственная&#039;&#039;]] локальность. Отмечаются позитивные и негативные факты, связанные с локальностью, какие ситуации и при каких условиях могут возникать. Исследуется, как меняется локальность при переходе от последовательной реализации к параллельной. Выделяются ключевые шаблоны взаимодействия программы, реализующей описываемый алгоритм, с памятью. Отмечается возможная взаимосвязь между используемыми конструкциями языков программирования и степенью локальности, которыми обладают результирующие программы. &lt;br /&gt;
&lt;br /&gt;
Отдельно приводятся профили взаимодействия с памятью для вычислительных ядер и ключевых фрагментов. Если из-за большого числа обращений по общему профилю сложно понять реальную специфику взаимодействия программ с памятью, то проводится последовательная детализация и приводится серия профилей более мелкого масштаба. &lt;br /&gt;
&lt;br /&gt;
На рис.3 и рис.4 показаны профили обращения в память для программ, реализующих разложение Холецкого и быстрое преобразование Фурье, по которым хорошо видна разница свойств локальности у данных алгоритмов.&lt;br /&gt;
&lt;br /&gt;
[[file:Cholesky_locality1.jpg|thumb|center|700px|Рис.3 Реализация метода Холецкого. Общий профиль обращений в память]]&lt;br /&gt;
[[file:fft 1.PNG|thumb|center|700px|Рис.4 Нерекурсивная реализация БПФ для степеней двойки. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Задача данного раздела - показать пределы [[глоссарий#Масштабируемость|&#039;&#039;масштабируемости&#039;&#039;]] алгоритма на различных платформах. Очень важный раздел. Нужно выделить, описать и оценить влияние точек барьерной синхронизации, глобальных операций, операций сборки/разборки данных, привести оценки или провести исследование [[глоссарий#Сильная масштабируемость|&#039;&#039;сильной&#039;&#039;]] и [[глоссарий#Слабая масштабируемость|&#039;&#039;слабой&#039;&#039;]] масштабируемости алгоритма и его реализаций.&lt;br /&gt;
&lt;br /&gt;
Масштабируемость алгоритма определяет свойства самого алгоритма безотносительно конкретных особенностей используемого компьютера. Она показывает, насколько параллельные свойства алгоритма позволяют использовать возможности растущего числа процессорных элементов. Масштабируемость параллельных программ определяется как относительно конкретного компьютера, так и относительно используемой технологии программирования, и в этом случае она показывает, насколько может вырасти реальная производительность данного компьютера на данной программе, записанной с помощью данной технологии программирования, при использовании бóльших вычислительных ресурсов (ядер, процессоров, вычислительных узлов).&lt;br /&gt;
&lt;br /&gt;
Ключевой момент данного раздела заключается в том, чтобы показать &#039;&#039;реальные параметры масштабируемости программы&#039;&#039; для данного алгоритма на различных вычислительных платформах в зависимости от числа процессоров и размера задачи &amp;lt;ref&amp;gt;Антонов А.С., Теплов А.М. О практической сложности понятия масштабируемости параллельных программ// Высокопроизводительные параллельные вычисления на кластерных системах (HPC 2014): Материалы XIV Международной конференции -Пермь: Издательство ПНИПУ, 2014. С. 20-27.&amp;lt;/ref&amp;gt;. При этом важно подобрать такое соотношение между числом процессоров и размером задачи, чтобы отразить все характерные точки в поведении параллельной программы, в частности, достижение максимальной производительности, а также тонкие эффекты, возникающие, например, из-за блочной структуры алгоритма или иерархии памяти.&lt;br /&gt;
&lt;br /&gt;
На рис.5. показана масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи. На графике хорошо видны области с большей производительностью, отвечающие уровням кэш-памяти.&lt;br /&gt;
[[file:Масштабируемость перемножения матриц производительность.png|thumb|center|700px|Рис.5 Масштабируемость классического алгоритма умножения плотных матриц в зависимости от числа процессоров и размера задачи]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
Это объемный раздел AlgoWiki, поскольку оценка эффективности реализации алгоритма требует комплексного подхода &amp;lt;ref&amp;gt;Никитенко Д.А. Комплексный анализ производительности суперкомпьютерных систем, основанный на данных системного мониторинга // Вычислительные методы и программирование. 2014. 15. 85–97.&amp;lt;/ref&amp;gt;, предполагающего аккуратный анализ всех этапов от архитектуры компьютера до самого алгоритма. Основная задача данного раздела заключается в том, чтобы оценить степень эффективности параллельных программ, реализующих данный алгоритм на различных платформах, в зависимости от числа процессоров и размера задачи. Эффективность в данном разделе понимается широко: это и [[глоссарий#Эффективность распараллеливания|&#039;&#039;эффективность распараллеливания&#039;&#039;]] программы, это и [[глоссарий#Эффективность реализации|&#039;&#039;эффективность реализации&#039;&#039;]] программ по отношению к пиковым показателям работы вычислительных систем. &lt;br /&gt;
&lt;br /&gt;
Помимо собственно показателей эффективности, нужно описать и все основные причины, из-за которых эффективность работы параллельной программы на конкретной вычислительной платформе не удается сделать выше. Это не самая простая задача, поскольку на данный момент нет общепринятой методики и соответствующего инструментария, с помощью которых подобный анализ можно было бы провести. Требуется оценить и описать эффективность работы с памятью (особенности профиля взаимодействия программы с памятью), эффективность использования заложенного в алгоритм ресурса параллелизма, эффективность использования коммуникационной сети (особенности коммуникационного профиля), эффективность операций ввода/вывода и т.п. Иногда достаточно интегральных характеристик по работе программы, в некоторых случаях полезно показать данные мониторинга нижнего уровня, например, по загрузке процессора, кэш-промахам, интенсивности использования сети Infiniband и т.п. Хорошее представление о работе параллельной MPI-программы дают данные трассировки, полученные, например, с помощью системы Scalasca.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Это объемный раздел AlgoWiki, поскольку оценка эффективности реализации алгоритма требует комплексного подхода &amp;lt;ref&amp;gt;Никитенко Д.А. Комплексный анализ производительности суперкомпьютерных систем, основанный на данных системного мониторинга // Вычислительные методы и программирование. 2014. 15. 85–97.&amp;lt;/ref&amp;gt;, предполагающего аккуратный анализ всех этапов от архитектуры компьютера до самого алгоритма. Основная задача данного раздела заключается в том, чтобы оценить степень эффективности параллельных программ, реализующих данный алгоритм на различных платформах, в зависимости от числа процессоров и размера задачи. Эффективность в данном разделе понимается широко: это и [[глоссарий#Эффективность распараллеливания|&#039;&#039;эффективность распараллеливания&#039;&#039;]] программы, это и [[глоссарий#Эффективность реализации|&#039;&#039;эффективность реализации&#039;&#039;]] программ по отношению к пиковым показателям работы вычислительных систем. &lt;br /&gt;
&lt;br /&gt;
Помимо собственно показателей эффективности, нужно описать и все основные причины, из-за которых эффективность работы параллельной программы на конкретной вычислительной платформе не удается сделать выше. Это не самая простая задача, поскольку на данный момент нет общепринятой методики и соответствующего инструментария, с помощью которых подобный анализ можно было бы провести. Требуется оценить и описать эффективность работы с памятью (особенности профиля взаимодействия программы с памятью), эффективность использования заложенного в алгоритм ресурса параллелизма, эффективность использования коммуникационной сети (особенности коммуникационного профиля), эффективность операций ввода/вывода и т.п. Иногда достаточно интегральных характеристик по работе программы, в некоторых случаях полезно показать данные мониторинга нижнего уровня, например, по загрузке процессора, кэш-промахам, интенсивности использования сети Infiniband и т.п. Хорошее представление о работе параллельной MPI-программы дают данные трассировки, полученные, например, с помощью системы Scalasca.&lt;br /&gt;
&lt;br /&gt;
=== Результаты прогонов ===&lt;br /&gt;
&lt;br /&gt;
В данном разделе приводятся результаты прогонов данной программной реализации на различных программно-аппаратных платформах.&lt;br /&gt;
&lt;br /&gt;
[[en:Description of implementation properties and structure]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:Main_page/Work&amp;diff=29621</id>
		<title>Шаблон:Main page/Work</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:Main_page/Work&amp;diff=29621"/>
		<updated>2024-12-04T08:54:17Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Структура описания свойств алгоритмов]]&lt;br /&gt;
* [[Структура описания свойств программных реализаций]]&lt;br /&gt;
* [[Руководства|Руководства по заполнению разделов описания]]&lt;br /&gt;
* [[Готовность статей]]&lt;br /&gt;
* [[Глоссарий]]&lt;br /&gt;
* [[Алговики:Справка|Помощь]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:GSA&amp;diff=29597</id>
		<title>Участник:GSA</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:GSA&amp;diff=29597"/>
		<updated>2024-07-03T11:13:33Z</updated>

		<summary type="html">&lt;p&gt;ASA: Создана пустая страница&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Cholesky_decomposition,_scalability&amp;diff=29342</id>
		<title>Cholesky decomposition, scalability</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Cholesky_decomposition,_scalability&amp;diff=29342"/>
		<updated>2022-12-05T09:22:03Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Teplov|А.М.Теплов]] (раздел [[#Масштабируемость алгоритма и его реализации|3]]).&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
[https://gitlab.srcc.msu.ru/alex-teplov/Scalability/tree/master/cholesky-decomposition-master Исследованная параллельная реализация на языке C].&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;
&lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации разложения Холецкого согласно [[Scalability methodology|методике]]. &lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [4 : 256] с шагом 4;&lt;br /&gt;
*	размер матрицы [1024 : 5120].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,11%;&lt;br /&gt;
*	максимальная эффективность реализации 2,65%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации разложения Холецкого в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость Параллельной реализации метода Холецкого Производительность3.png|thumb|center|700px|Рисунок 1. Параллельная реализация метода Холецкого. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file:Холецкий масштабируемость эффективность2.png|thumb|center|700px|Рисунок 2. Параллельная реализация метода Холецкого. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации разложения Холецкого:&lt;br /&gt;
*	По числу процессов: -0,000593. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска уменьшается, однако в целом уменьшение не очень быстрое. Малая интенсивность изменения объясняется крайне низкой общей эффективностью работы приложения с максимумом в 2,65%, и значение эффективности на рассмотренной области значений быстро доходит до десятых долей процента. Это свидетельствует о том, что на большей части области значений нет интенсивного снижения эффективности. Это объясняется также тем, что с ростом [[Глоссарий#Вычислительная сложность|вычислительной сложности]] падение эффективности становится не таким быстрым. Уменьшение эффективности на рассмотренной области работы параллельной программы объясняется быстрым ростом накладных расходов на организацию параллельного выполнения. С ростом вычислительной сложности задачи эффективность снижается так же быстро, но при больших значениях числа процессов. Это подтверждает предположение о том, что накладные расходы начинают сильно превалировать над вычислениями.&lt;br /&gt;
*	По размеру задачи: 0,06017. При увеличении размера задачи эффективность возрастает. Эффективность возрастает тем быстрее, чем большее число процессов используется для выполнения. Это подтверждает предположение о том, что размер задачи сильно влияет на эффективность выполнения приложения. Оценка показывает, что с ростом размера задачи эффективность на рассмотренной области значений параметров запуска сильно увеличивается. Также, учитывая разницу максимальной и минимальной эффективности в 2,5%, можно сделать вывод, что рост эффективности при увеличении размера задачи наблюдается на большей части рассмотренной области значений.&lt;br /&gt;
*	По двум направлениям: 0,000403. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая. В совокупности с тем фактом, что разница между максимальной и минимальной эффективностью на рассмотренной области значений параметров небольшая, эффективность с увеличением масштабов возрастает, но медленно и с небольшими перепадами.&lt;br /&gt;
&lt;br /&gt;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Cholesky decomposition, scalability]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=PageRank,_VGL&amp;diff=29340</id>
		<title>PageRank, VGL</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=PageRank,_VGL&amp;diff=29340"/>
		<updated>2022-11-28T12:20:44Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания:   = Ссылки =  https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/pr/pr...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: &lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/pr/pr.hpp (функция vgl_page_rank).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:PageRank, VGL]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=HITS,_VGL&amp;diff=29339</id>
		<title>HITS, VGL</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=HITS,_VGL&amp;diff=29339"/>
		<updated>2022-11-28T12:13:44Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания:   = Ссылки =  https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/hits/...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: &lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/hits/hits.hpp  (функция vgl_hits).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:HITS, VGL]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_pull&amp;diff=29338</id>
		<title>Dijkstra, VGL, pull</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_pull&amp;diff=29338"/>
		<updated>2022-11-28T06:39:02Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: .  = Ссылки =  https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sssp...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: .&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sssp/shortest_paths.hpp (функция &amp;lt;code&amp;gt;vgl_dijkstra_all_active_pull&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dijkstra, VGL, pull]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_push&amp;diff=29337</id>
		<title>Dijkstra, VGL, push</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_push&amp;diff=29337"/>
		<updated>2022-11-28T06:37:27Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: .&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sssp/shortest_paths.hpp (функция &amp;lt;code&amp;gt;vgl_dijkstra_all_active_push&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dijkstra, VGL, push]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_push&amp;diff=29336</id>
		<title>Dijkstra, VGL, push</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_push&amp;diff=29336"/>
		<updated>2022-11-28T06:34:53Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: .&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
[https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sssp/shortest_paths.hpp]https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sssp/shortest_paths.hpp (функция &amp;lt;code&amp;gt;vgl_dijkstra_all_active_push&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dijkstra, VGL, push]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_push&amp;diff=29335</id>
		<title>Dijkstra, VGL, push</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Dijkstra,_VGL,_push&amp;diff=29335"/>
		<updated>2022-11-28T06:30:49Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: .  = Ссылки =  [https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sss...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: .&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
[https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/sssp/shortest_paths.hpp] (функция &amp;lt;code&amp;gt;vgl_dijkstra_all_active_push&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Dijkstra, VGL, push]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=BFS,_VGL&amp;diff=29334</id>
		<title>BFS, VGL</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=BFS,_VGL&amp;diff=29334"/>
		<updated>2022-11-25T13:26:12Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания:   = Ссылки =  https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/bfs/b...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: &lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
https://github.com/afanasyev-ilya/VectorGraphLibrary/blob/master/algorithms/bfs/bfs.hpp  (первая функция BFS::fast_vgl_top_down).&lt;br /&gt;
&lt;br /&gt;
Описание библиотеки VGL: https://vgl.parallel.ru/documentation.html&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:BFS, VGL]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%B2%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%B8_%D0%BF%D0%BE%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5&amp;diff=29248</id>
		<title>Метод встречи посередине</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%B2%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%B8_%D0%BF%D0%BE%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5&amp;diff=29248"/>
		<updated>2022-07-21T13:24:55Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор описания (разделы 1, 2.4, 2.7):&lt;br /&gt;
[https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Метод встречи посередине&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(\sqrt n\log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(1)&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;O(\log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;\log(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;quot;атакой&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Метод &amp;quot;Встреча посередине&amp;quot; криптоанализа блочных шифров был впервые предложен в 1977 году Уитфилдом Диффи и Мартином Хеллманом &amp;lt;ref&amp;gt;Diffie Whitfield, Hellman Martin E. &#039;&#039;Exhaustive Cryptanalysis of the NBS Data Encryption Standard.&#039;&#039; - Journal Computer vol.10 pp.74–84 - June 1977&amp;lt;/ref&amp;gt;. Встреча посередине используется для ускорения перебора ключей шифра за счёт увеличения требуемой памяти. Метод применим в случае каскадного построения сложного шифра из нескольких простых, другими словами, в случае последовательного применения шифрующих преобразований на разных ключах к блокам открытого текста.&lt;br /&gt;
&lt;br /&gt;
В качестве примера шифра, поддающегося атаке &amp;quot;встреча посередине&amp;quot; можно привести криптоалгоритм 2DES, являющийся модификацией шифра DES. В 2DES открытый текст шифруется дважды алгоритмом DES на двух разных 56-битных ключах. Однако из-за атаки &amp;quot;встреча посередине&amp;quot; сложность перебора двойного ключа (112 бит) шифра 2DES составляет &amp;lt;math&amp;gt;2^{57}&amp;lt;/math&amp;gt; вместо ожидаемых &amp;lt;math&amp;gt;2^{112}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039; открытый текст &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;, шифртекст &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Алгоритм зашифрования — композиция двух преобразований: &amp;lt;math&amp;gt;T_1(x,k_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T_2(x,k_2)&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;y=T_2(T_1(x,k_1),k_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Алгоритм расшифрования: &amp;lt;math&amp;gt;y=T_1^{-1}(T_2^{-1}(x,k_2),k_1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вычисляемые данные:&#039;&#039;&#039; ключи шифрования &amp;lt;math&amp;gt;k_1 \in K_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;k_2 \in K_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;K_1, K_2&amp;lt;/math&amp;gt; — множества возможных ключей.&lt;br /&gt;
&lt;br /&gt;
Трудоёмкость полного перебора всех возможных пар &amp;lt;math&amp;gt;k_1,k_2&amp;lt;/math&amp;gt; составляет в среднем &amp;lt;math&amp;gt;|K_1||K_2|/2&amp;lt;/math&amp;gt;, а в худшем случае &amp;lt;math&amp;gt;|K_1||K_2|&amp;lt;/math&amp;gt;. Однако используя дополнительную память, можно сократить перебор.&lt;br /&gt;
&lt;br /&gt;
Предположим, что открытый текст &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и шифртекст &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; однозначно определяют ключи &amp;lt;math&amp;gt;k_1,k_2&amp;lt;/math&amp;gt;. Составим две таблицы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
z_1 &amp;amp; =T_1(x,k_1^1) &amp;amp; z_1^&amp;amp;prime; &amp;amp;=T_2^{-1}(x,k_2^1)\\&lt;br /&gt;
z_2 &amp;amp; =T_1(x,k_1^2) &amp;amp; z_2^&amp;amp;prime; &amp;amp; =T_2^{-1}(x,k_2^2)\\&lt;br /&gt;
 &amp;amp; ......... &amp;amp;  &amp;amp; ......... \\&lt;br /&gt;
z_{|K_1|} &amp;amp; =T_1(x,k_1^{|K_1|}) &amp;amp; z_{|K_1|}^&amp;amp;prime; &amp;amp; =T_2^{-1}(x,k_2^{|K_1|})&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для всех &amp;lt;math&amp;gt;k_1^i \in K_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;k_2^j \in K_2&amp;lt;/math&amp;gt;. Далее таблицы объединяются и сортируются по значениям &amp;lt;math&amp;gt;z_i,z_j^&amp;amp;prime;&amp;lt;/math&amp;gt;. Индексы &amp;lt;math&amp;gt;i,j&amp;lt;/math&amp;gt;, при которых &amp;lt;math&amp;gt;z_i=z_j^&amp;amp;prime;&amp;lt;/math&amp;gt;, однозначно определяют искомую пару ключей &amp;lt;math&amp;gt;k_1=k_1^i,k_2=k_2^j&amp;lt;/math&amp;gt;. Для нахождения такой пары достаточно просмотреть отсортированную таблицу один раз.&lt;br /&gt;
&lt;br /&gt;
Если же пара открытый текст/шифртекст определяет ключ не единственном образом, то выходом алгоритма будет некоторое множество пар &amp;lt;math&amp;gt;k_1,k_2&amp;lt;/math&amp;gt;, одна из которых является истинным ключом. Для выбора истинного ключа достаточно проверить ключи из полученного множества на других парах открытый текст/шифртекст.&lt;br /&gt;
&lt;br /&gt;
==== Оптимизации ====&lt;br /&gt;
&lt;br /&gt;
1. От генерации второй таблицы со значениями &amp;lt;math&amp;gt;z_j^&amp;amp;prime;&amp;lt;/math&amp;gt; можно отказаться, перебирая ключи &amp;lt;math&amp;gt;k_2^j&amp;lt;/math&amp;gt; до того момента, когда значение &amp;lt;math&amp;gt;z_j^&amp;amp;prime;&amp;lt;/math&amp;gt; совпадёт с одним из значений &amp;lt;math&amp;gt;z_i&amp;lt;/math&amp;gt;. В таком случае опробование ключей &amp;lt;math&amp;gt;k_2^j&amp;lt;/math&amp;gt; в среднем сократится вдвое. Также вдвое сократится объём используемой памяти. Для нахождения совпадающего значения в отсортированном массиве можно применить бинарный поиск.&lt;br /&gt;
&lt;br /&gt;
2. Вместо сортировки таблицы со значениями &amp;lt;math&amp;gt;z_i&amp;lt;/math&amp;gt; и последующего бинарного поиска можно использовать хэш-таблицу.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
В случае использования хэш-таблицы достаточно большого размера основную сложность алгоритма составляет опробование ключей &amp;lt;math&amp;gt;k_1,k_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
Одним из самых трудоёмких шагов также оказывается сортировка таблицы.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из описания, атака &amp;quot;встреча посередине&amp;quot; использует (или может использовать в качестве оптимизации) следующие алгоритмы:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм зашифрования/расшифрования&lt;br /&gt;
&lt;br /&gt;
2. Алгоритм сортировки&lt;br /&gt;
&lt;br /&gt;
3. Алгоритмы поиска, вставки в хэш-таблицу&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Далее приводится последовательность действий для варианта алгоритма с генерацией одной таблицы значений &amp;lt;math&amp;gt;z_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
1. Вычислить таблицу &amp;lt;math&amp;gt;z_i&amp;lt;/math&amp;gt;, записывая значения в порядке вычисления или используя хэш-таблицу&lt;br /&gt;
&lt;br /&gt;
2. В случае записи значений в порядке вычисления отсортировать массив&lt;br /&gt;
&lt;br /&gt;
3. Опробовать ключи &amp;lt;math&amp;gt;k_2^j&amp;lt;/math&amp;gt;, выполняя поиск совпадения с таблицей значений &amp;lt;math&amp;gt;z_j^&amp;amp;prime;&amp;lt;/math&amp;gt;. Для нахождения совпадения использовать поиск по хэш-таблице (если она есть) или бинарный поиск&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Всюду далее считаем, что алгоритм не прекращает работу при нахождении первого совпадения, а ищет все совпадения.&lt;br /&gt;
&lt;br /&gt;
1. Сложность вычисления таблиц значений &amp;lt;math&amp;gt;z_i,z_j^&amp;amp;prime;&amp;lt;/math&amp;gt; составит &amp;lt;math&amp;gt;O(|K_1|+|K_2|)&amp;lt;/math&amp;gt; операций опробования &lt;br /&gt;
&lt;br /&gt;
2. Объединение таблиц и их сортировка будет иметь сложность &amp;lt;math&amp;gt;O((|K_1|+|K_2|)\log(|K_1|+|K_2|))&amp;lt;/math&amp;gt; (например, при сортировке слиянием).&lt;br /&gt;
&lt;br /&gt;
3. Сложность бинарного поиска в отсортированном массиве — &amp;lt;math&amp;gt;O(\log_2(|K_1|))&amp;lt;/math&amp;gt; для каждого поиска&lt;br /&gt;
&lt;br /&gt;
4. Сложность поиска в достаточно большой хэш-таблице составит &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; для каждого поиска&lt;br /&gt;
&lt;br /&gt;
Итого: асимптотическая сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
1. С генерацией двух таблиц — &amp;lt;math&amp;gt;O(|K_1|+|K_2|) + O((|K_1|+|K_2|)\log(|K_1|+|K_2|)) + O(|K_1|+|K_2|)=O((|K_1|+|K_2|)\log(|K_1|+|K_2|))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. C генерацией одной таблицы, сортировкой и бинарным поиском — &amp;lt;math&amp;gt;O(|K_1|) + O((|K_1|)\log(|K_1|)) + O(|K_2|\log_2(|K_1|))=O(\max(|K_1|,|K_2|)\log(|K_1|))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. C генерацией одной (достаточно большой) хэш-таблицы — &amp;lt;math&amp;gt;O(|K_1|) + O(|K_2|)=O(|K_1|+|K_2|)&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;k_1,k_2&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;|K_1|=|K_2|&amp;lt;/math&amp;gt;. В этом случае &amp;lt;math&amp;gt;|K_1|=|K_2|=\sqrt n&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Тогда сложность алгоритма в первых двух пунктах составляет &amp;lt;math&amp;gt;O(\sqrt n\log(n))&amp;lt;/math&amp;gt;, в третьем — &amp;lt;math&amp;gt;O(\sqrt n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем информационный граф алгоритма. На вход подаётся открытый (Open) и закрытый (Close), т.е. зашифрованный, текст. Далее открытый текст шифруется (Enc) на ключах &amp;lt;math&amp;gt;k_1^i&amp;lt;/math&amp;gt;, а зашифрованный расшифровывается (Dec) на ключах &amp;lt;math&amp;gt;k_2^j&amp;lt;/math&amp;gt;. Далее полученные криптограммы сравниваются (Cmp) и все ключи, на которых они совпали, являются выходом алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[file:meet.png|thumb|center|900px|Рисунок 1. Граф алгоритма c отображением входных и выходных данных. Open — открытый текст, Close — шифртекст, Enc — операция зашифрования, Dec — операция расшифрования, Cmp — операция сравнения, Keys — вычисленные ключи]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из информационного графа, для реализации атаки &amp;quot;встреча посередине&amp;quot; в параллельном варианте потребуются выполнение следующих двух ярусов (в предположении, что &amp;lt;math&amp;gt;|K_1|=|K_2|&amp;lt;/math&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
1. &amp;lt;math&amp;gt;\sqrt n&amp;lt;/math&amp;gt; зашифрований и столько же расшифрований&lt;br /&gt;
&lt;br /&gt;
2. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Таким образом, высота ЯПФ составляет 2, ширина - &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вход:&#039;&#039;&#039;&lt;br /&gt;
На вход подаётся открытый текст &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и шифртекст &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;, а также алгоритм зашифрования/расшифрования. В случае блочного шифра открытым текстом и шифртекстом является последовательность блоков. Для атаки &amp;quot;встреча посередине&amp;quot;, как правило, берётся один блок для максимального ускорения операций зашифрования и расшифрования.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выход:&#039;&#039;&#039;&lt;br /&gt;
Результатом работы алгоритма является множество пар &amp;lt;math&amp;gt;k_1^i,k_2^j&amp;lt;/math&amp;gt;, для которых нашлись совпадения. Только одна из пар является настоящим ключом. Чтобы отсеять лишние, необходимо проверить все пары на блоках открытого и шифрованного текста, которые в алгоритме не использовались.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Соотношением последовательной и параллельной сложности алгоритма является &amp;lt;math&amp;gt;O(\sqrt n\log(n))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем считать, что размер входных данных (открытый текст и шифртекст) совпадает с размером ключа (на практике это сравнимые величины), а сортировка слиянием делит массивы пополам. Тогда вычислительная мощность алгоритма — &amp;lt;math&amp;gt;O(\sqrt n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Дуги информационного графа, исходящие из вершин зашифрования и расшифрования, образуют пучки мощности &amp;lt;math&amp;gt;\sqrt n&amp;lt;/math&amp;gt;, т.е. из каждой такой вершины выходит &amp;lt;math&amp;gt;\sqrt n&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;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[en:Meet-in-the-middle attack]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_implementation3&amp;diff=29247</id>
		<title>Meet-in-the-middle attack, implementation3</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_implementation3&amp;diff=29247"/>
		<updated>2022-07-21T13:22:47Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;]....»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
В свободном доступе существует код для метода &amp;quot;встречи посередине&amp;quot; с использованием шифрования 2DES на [https://github.com/le1ca/class-resources/blob/master/ddes/ddes.py питоне].&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Meet-in-the-middle attack, implementation3]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_implementation2&amp;diff=29246</id>
		<title>Meet-in-the-middle attack, implementation2</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_implementation2&amp;diff=29246"/>
		<updated>2022-07-21T13:20:15Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;]....»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
В свободном доступе существует код для метода &amp;quot;встречи посередине&amp;quot; с использованием шифрования Blowfish и хэш-таблиц на [https://gist.github.com/dchest/1062437 C].&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Meet-in-the-middle attack, implementation2]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_implementation1&amp;diff=29245</id>
		<title>Meet-in-the-middle attack, implementation1</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_implementation1&amp;diff=29245"/>
		<updated>2022-07-21T13:17:48Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;]....»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
Одна из реализаций атаки &amp;quot;встреча посередине&amp;quot; с использованием хэш-таблицы представлена в свободном доступе по ссылке [https://gist.github.com/dchest/1062437 github].&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;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Meet-in-the-middle attack, implementation1]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_scalability&amp;diff=29244</id>
		<title>Meet-in-the-middle attack, scalability</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Meet-in-the-middle_attack,_scalability&amp;diff=29244"/>
		<updated>2022-07-21T13:14:38Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;]....»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [https://algowiki-project.org/ru/Участник:Александра&amp;lt;b&amp;gt;А.В.Батарина&amp;lt;/b&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
[https://github.com/AlBatarina/Super2016/blob/master/meet_in_the_middle/meet.c Исследованная параллельная реализация на языке C].&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;
&lt;br /&gt;
Исследование масштабируемости реализации алгоритма проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Изменяемые параметры запуска:&lt;br /&gt;
* Размер ключа – от 8 до 20 бит с шагом 1&lt;br /&gt;
* Число ядер – от 1 до 8 (значения являются степенью числа 2)&lt;br /&gt;
Ниже представлен график зависимости [[Глоссарий#Производительность|производительности]] от числа ядер и размера ключа (размер задачи – экспоненциальная функция от размера ключа). Для измерения производительности в качестве базовой операции используется операция опробования ключа и время в секундах. Количество арифметических операций, содержащихся в операции опробования, может быть разным в зависимости от используемого алгоритма шифрования.&lt;br /&gt;
[[File:Масштабируемость.jpg|thumb|center|900px|Рисунок 1. Масштабируемость реализации алгоритма]]&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Meet-in-the-middle attack, scalability]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29243</id>
		<title>Уравнение Пуассона, решение дискретным преобразованием Фурье</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%9F%D1%83%D0%B0%D1%81%D1%81%D0%BE%D0%BD%D0%B0,_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D1%8B%D0%BC_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%A4%D1%83%D1%80%D1%8C%D0%B5&amp;diff=29243"/>
		<updated>2022-07-21T12:55:44Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]].&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Уравнение Пуассона для многомерного пространства имеет вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\partial^2 \phi}{\partial x_i^2}=f,~\mathbf{x}\in D,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D \in \mathbb{R}^N&amp;lt;/math&amp;gt; - область определения решения &amp;lt;math&amp;gt;\phi(\mathbf{x})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathbf{x}=(x_1,...,x_N)^T&amp;lt;/math&amp;gt; - вектор независимых переменных. Уравнение Пуассона дополняется граничными условиями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
B(\phi)=F, \mathbf{x} \in \Gamma(D),&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt; - граница области &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, a &amp;lt;math&amp;gt;B(\phi)&amp;lt;/math&amp;gt; - оператор, определяющий граничные условия. &amp;lt;math&amp;gt;B(\phi)=\phi&amp;lt;/math&amp;gt; соответствует граничным условиям Дирихле, &amp;lt;math&amp;gt;B(\phi)=\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;\mathbf{n}&amp;lt;/math&amp;gt; - внешняя нормаль к границе &amp;lt;math&amp;gt;\Gamma(D)&amp;lt;/math&amp;gt;) - условиям Неймана. Иногда задают также смешанное граничное условие: &amp;lt;math&amp;gt;B(\phi)=C\phi+\partial\phi/\partial n&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; - константа). Встречаются также так называемые &amp;quot;периодические граничные условия&amp;quot;, при которых задача ставится для бесконечной области, но предполагается периодичность решения по подмножеству переменных из &amp;lt;math&amp;gt;\mathbf{x}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение Пуассона возникает во многих задачах математической физики, например, в электростатике (в этом случае &amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - потенциал электрической силы) и гидродинамике (&amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt; - давление жидкости или газа); при этом &amp;lt;math&amp;gt;N=2,3&amp;lt;/math&amp;gt; для плоской и трехмерной задач, соответственно.&lt;br /&gt;
&lt;br /&gt;
Решение уравнения Пуассона для произвольной правой части и неоднородных граничных условий в аналитическом виде неизвестно, поэтому в большинстве приложений оно находится численно. Наиболее распространенная дискретизация этого уравнения имеет вид&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\sum_{i=1}^{N}\frac{\phi_{k_1,...,k_i+1,...,k_N}-2\phi_{k_1,...,k_i,...,k_N}+\phi_{k_1,...,k_i-1,...,k_N}}{\Delta x_i^2}=f_{k_1,...,k_N},~(k_1,...,k_N) \in D_N. &lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь вторые производные заменены конечно-разностной аппроксимацией второго порядка точности (образуя т.н. схему &amp;quot;крест&amp;quot; для плоской задачи), а решение ищется на дискретном множестве точек &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;-мерного пространства, &amp;lt;math&amp;gt;D_N&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;&lt;br /&gt;
\frac{\phi_{i+1,j,k}-2\phi_{i,j,k}+\phi_{i-1,j,k}}{ \Delta x^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j+1,k}-2\phi_{i,j,k}+\phi_{i,j-1,k}}{ \Delta y^2}\,+\,&lt;br /&gt;
\frac{\phi_{i,j,k+1}-2\phi_{i,j,k}+\phi_{i,j,k-1}}{ \Delta z^2} = f_{i,j,k},~(i,j,k) \in D_h,&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;D_h=\{0:N_x-1\}\times\{0:N_y-1\}\times\{0:N_z-1\} &amp;lt;/math&amp;gt; - параллелепипед в сеточной области. В качестве граничных условий для простоты примем так называемые троякопериодические граничные условия&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{align}&lt;br /&gt;
\phi_{0,j,k} &amp;amp;= \phi_{N_x,j,k},\\&lt;br /&gt;
\phi_{i,0,k} &amp;amp;= \phi_{i,N_y,k},\\&lt;br /&gt;
\phi_{i,j,0} &amp;amp;= \phi_{i,j,N_z}.&lt;br /&gt;
\end{align}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Периодические граничные условия удовлетворяются &amp;quot;автоматически&amp;quot;, если представить решение в виде стандартного дискретного обратного преобразования Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x N_y N_z}\sum_{l=0}^{N_x-1}\sum_{m=0}^{N_y-1}\sum_{n=0}^{N_z-1}\Phi_{l,m,n}e^{2\pi \overline{i} &lt;br /&gt;
\left(\frac{il}{N_x}+\frac{jm}{N_y}+\frac{kn}{N_z}\right)}.&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;\overline{i}=\sqrt{-1}&amp;lt;/math&amp;gt;. Аналогичное разложение применяется также к правой части уравнения, &amp;lt;math&amp;gt;f_{i,j,k}&amp;lt;/math&amp;gt;. Решение дискретного уравнения Пуассона преобразованием Фурье удобно тем, что базисные функции разложения Фурье являются собственными функциями дискретного оператора Лапласа. А именно, подставляя разложение Фурье неизвестной функции &amp;lt;math&amp;gt;\phi_{i,j,k}&amp;lt;/math&amp;gt; и правой части в исходное уравнение, получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\Phi_{l,m,n}=-\frac{F_{l,m,n}}{4\left[\sin^2\left(\frac{\pi l}{N_x}\right) + \sin^2\left(\frac{\pi m}{N_y}\right) + \sin^2\left(\frac{\pi n}{N_z}\right) \right]},&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;F_{l,m,n}&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;&lt;br /&gt;
\phi_{i,j,k}=\frac{1}{N_x} \sum_{l=0}^{N_x-1} \left[ e^{2\pi \overline{i}\left(\frac{il}{N_x}\right)} &lt;br /&gt;
\frac{1}{N_y} \sum_{m=0}^{N_y-1} \left[ e^{2\pi \overline{i}\left(\frac{jm}{N_y}\right)}&lt;br /&gt;
\frac{1}{N_z} \sum_{n=0}^{N_z-1} \Phi_{l,m,n}e^{2\pi \overline{i} \left(\frac{kn}{N_z}\right)}\right]\right],&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
откуда видно, что трехмерное преобразование Фурье сводится в последовательности трех одномерных. Для вычисления одномерного преобразования широко используется эффективный алгоритм быстрого преобразования Фурье (БПФ, FFT, Fast Fourier Transform)&amp;lt;ref&amp;gt;Марчук Г.И. Методы вычислительной математики, М., 1977, 456с.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Из приведенного выше ясно, что основной макрооперацией алгоритма решения уравнения Пуассона является одномерное быстрое преобразование Фурье. В дальнейшем будем обозначать ее &amp;lt;math&amp;gt;\text{FFT}_i,~i=x,y,z&amp;lt;/math&amp;gt; по каждому из трех направлений, соответственно, а обратное преобразование Фурье - &amp;lt;math&amp;gt;\text{IFFT}_i,~i=x,y,z&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Введем для краткости следующие обозначения сеточных функций:&lt;br /&gt;
&amp;lt;math&amp;gt;\phi_h=\{\phi_{i,j,k},~(i,j,k) \in D_h\},~F_h=\{F_{l,m,n},~l=0,...,N_x-1,~m=0,...,N_y-1,~n=0,...,N_z-1\}&amp;lt;/math&amp;gt; и аналогично &amp;lt;math&amp;gt;f_h&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда алгоритм запишется следующим образом:&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_x(f_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_y(\text{FFT}_x(f_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{FFT}_z(\text{FFT}_y(\text{FFT}_x(f_h)))=F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Расчет &amp;lt;math&amp;gt;\Phi_h&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;F_h&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_x(\Phi_h)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_y(\text{IFFT}_x(\Phi_h))&amp;lt;/math&amp;gt;&lt;br /&gt;
# Вычисление &amp;lt;math&amp;gt;\text{IFFT}_z(\text{IFFT}_y(\text{IFFT}_x(\Phi_h)))=\phi_h&amp;lt;/math&amp;gt;&lt;br /&gt;
Примечательно, что весь описанный алгоритм реализуется с помощью одного трехмерного массива &amp;lt;math&amp;gt;N_x \times N_y \times N_z&amp;lt;/math&amp;gt;, поскольку результат каждого одномерного преобразования Фурье можно записать во входной массив и затем использовать его на входе для следующего преобразования, а операция (4) - это поэлементное изменение массива.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма === &lt;br /&gt;
&lt;br /&gt;
Рассмотрим случай куба, &amp;lt;math&amp;gt;N_x=N_y=N_z=N=2^k&amp;lt;/math&amp;gt;. Тогда сложность одномерного БПФ по каждому из направлений составляет (по порядку) &amp;lt;math&amp;gt;N(\text{log}_2 N)&amp;lt;/math&amp;gt; операций. Поскольку одномерное БПФ на каждом из этапов алгоритма, кроме четвертого, осуществляется &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; раз, а количество операций на этапе 4 составляет (снова по порядку) &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt;, то общее количество арифметических действий составляет &amp;lt;math&amp;gt;N^3(6\text{log}_2 N+1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Представим информационный граф алгоритма для этапов 1-4, поскольку этапы 5-7 реализуются аналогично этапам 1-3.&lt;br /&gt;
&lt;br /&gt;
[[File:pois3d_graph.png|center|thumb|600px|Зеленые прямоугольники обозначают одномерные сечения входного трехмерного массива. Красным кругом обозначена операция одномерного БПФ, например &amp;lt;math&amp;gt;FFT_{x11}&amp;lt;/math&amp;gt; означает БПФ вдоль оси x при &amp;lt;math&amp;gt;j=1,~k=1&amp;lt;/math&amp;gt;. Желтыми кругами представлены поэлементные преобразования массива для получения коэффициентов Фурье решения (этап 4 алгоритма), например &amp;lt;math&amp;gt;L_{2N,1,...,N}&amp;lt;/math&amp;gt; означает преобразование элементов &amp;lt;math&amp;gt;i=2,~j=N,~k=1,...,N&amp;lt;/math&amp;gt;. Для удобства целочисленные индексы нумеруются числами &amp;lt;math&amp;gt;1,...,N&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;0,...,N-1&amp;lt;/math&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Информационная зависимость между ярусами графа заключается в том, что одномерное БПФ зависит от результата произведенного ранее БПФ по перпендикулярному направлению (т.е. с предыдущего яруса), только если обрабатываемые этими БПФ одномерные сечения массива пересекаются. Следовательно, каждое из БПФ по второй координате, &amp;lt;math&amp;gt;FFT_{i,y,k},~i=1,...,N&amp;lt;/math&amp;gt;, зависит от результатов каждого из БПФ по первой координате &amp;lt;math&amp;gt;FFT_{x,j,k},~j=1,...,N&amp;lt;/math&amp;gt;, и только от них, если эти преобразования производятся в одной плоскости &amp;lt;math&amp;gt;k=K&amp;lt;/math&amp;gt;. Соответственно, каждое БПФ по третьей координате &amp;lt;math&amp;gt;FFT_{i,j,z},~j=1,...,N&amp;lt;/math&amp;gt;, зависит от каждого БПФ по второй координате &amp;lt;math&amp;gt;FFT_{i,y,k},~k=1,...,N&amp;lt;/math&amp;gt;, в одной плоскости &amp;lt;math&amp;gt;i=I&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном выше алгоритме можно выделить, по меньшей мере, два уровня параллелизма. Во-первых, вычисление каждого одномерного БПФ может быть распределено между вычислительными ядрами. И, во-вторых, на каждом этапе алгоритма (ярусе графа) одномерные БПФ независимы друг от друга и также могут быть выполнены паралельно (координатный параллелизм). Для сопоставления параллельной (при координатном распараллеливании) и последовательной сложности алгоритма определим в качестве основных операций одномерное БПФ и поэлементный перерасчет массива (этап 4 алгоритма). Тогда последовательный алгоритм будет состоять из последовательно выполняемых &amp;lt;math&amp;gt;6N^2&amp;lt;/math&amp;gt; одномерных БПФ и &amp;lt;math&amp;gt;N^3&amp;lt;/math&amp;gt; операций над отдельными элементами массива, параллельный же алгоритм будет выполнен за 6 шагов одномерного БПФ и 1 операцию поэлементного преобразования. Если же выразить введенные макрооперации через элементарные арифметические операции, то получим, что сложность последовательного алгоритма - &amp;lt;math&amp;gt;6N^3(\text{log}_2N)+N^3&amp;lt;/math&amp;gt;, а сложность параллельного - &amp;lt;math&amp;gt;6N(\text{log}_2N)+1&amp;lt;/math&amp;gt;. Тогда при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; отношение последовательной сложности к параллельной становится равным &amp;lt;math&amp;gt;\propto N^2(6\text{log}_2N \text{ln}2+\text{ln}2+5)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
В качестве входных данных выступает трехмерный массив &amp;lt;math&amp;gt;N \times N \times N&amp;lt;/math&amp;gt; правой части уравнения. Выходной массив - трехмерный массив решения той же размерности.&lt;br /&gt;
&lt;br /&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;N^3&amp;lt;/math&amp;gt;, вычислительная мощность последовательного алгоритма становится равной &amp;lt;math&amp;gt;6\text{log}_2N+1&amp;lt;/math&amp;gt;, а параллельного алгоритма - &amp;lt;math&amp;gt;(6N\text{log}_2N+1)/N^3 \propto N^{-2}&amp;lt;/math&amp;gt; (при больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Приведем пример реализации алгоритма на языке Фортран-90 с применением библиотеки  [http://www.fftw.org/ FFTW]. &lt;br /&gt;
В этом случае трехмерное прямое преобразование Фурье правой части уравнения реализуется как последовательность трех одномерных (этапы 1-3 в п.1.5). &lt;br /&gt;
Полученные коэффициенты Фурье делятся на собственное число оператора Лапласа (этап 4 в п.1.5) (см. комментарии в коде):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workfor_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_x,workfor_x,workfor_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workfor_x(1:i1)) )&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workfor_x(1:i1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_y,workfor_y,workfor_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workfor_y(1:j1)) )&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workfor_y(1:j1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! z - transform and dividing by eigenvalue&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workfor_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planfor_z,workfor_z,workfor_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workfor_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workfor_z(1:k1)) )&lt;br /&gt;
             ! Dividing by eigenvalue of Laplace operator&lt;br /&gt;
             sinx = sin((i-1) * Pi / i1)^2 * 4&lt;br /&gt;
             siny = sin((j-1) * Pi / j1)^2 * 4&lt;br /&gt;
             do k = 1, k1&lt;br /&gt;
               sinz = sin((k-1) * Pi / k1)^2 * 4&lt;br /&gt;
               f_r(i,j,1:k1) = f_r(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
               f_i(i,j,1:k1) = f_i(i,j,1:k1)/(sinx + siny + sinz)&lt;br /&gt;
             enddo&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как только коэффициенты Фурье решения найдены, аналогично производится обратное преобразование Фурье:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
         ! inverse x - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do j = 1, j1&lt;br /&gt;
             workback_x(1:i1) = cmplx(f_r(1:i1,j,k),f_i(1:i1,j,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_x,workback_x,workback_x)&lt;br /&gt;
             f_r(1:i1,j,k) = real(real (workback_x(1:i1)) )/real(i1)&lt;br /&gt;
             f_i(1:i1,j,k) = real(aimag(workback_x(1:i1)) )/real(i1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse y - transform&lt;br /&gt;
         do k = 1, k1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_y(1:j1) = cmplx(f_r(i,1:j1,k),f_i(i,1:j1,k))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_y,workback_y,workback_y)&lt;br /&gt;
             f_r(i,1:j1,k) = real(real (workback_y(1:j1)) )/real(j1)&lt;br /&gt;
             f_i(i,1:j1,k) = real(aimag(workback_y(1:j1)) )/real(j1)&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
         ! inverse z - transform&lt;br /&gt;
         do j = 1, j1&lt;br /&gt;
           do i = 1, i1&lt;br /&gt;
             workback_z(1:k1) = cmplx(f_r(i,j,1:k1),f_i(i,j,1:k1))&lt;br /&gt;
             call FFTW_EXECUTE_DFT(planback_z,workback_z,workback_z)&lt;br /&gt;
             f_r(i,j,1:k1) = real(real (workback_z(1:k1)) )&lt;br /&gt;
             f_i(i,j,1:k1) = real(aimag(workback_z(1:k1)) )&lt;br /&gt;
           enddo&lt;br /&gt;
         enddo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как видим, вложенность циклов соответствует порядку расположения элементов массивов в языке Фортран - по столбцам - это позволяет существенно сократить время обращения к памяти.&lt;br /&gt;
Многократно используются одни и те же вспомогательные массивы, что при небольших размерах сетки должно обеспечить быстроту работы с кэш-памятью. &lt;br /&gt;
Однако, данная реализация не является оптимальной. Так, вместо многократного вызова подпрограммы FFTW_EXECUTE_DFT в циклах, можно было бы обращаться к одной подпрограмме, выполняющей&lt;br /&gt;
заданное множество одномерных БПФ.&lt;br /&gt;
&lt;br /&gt;
Из приведенных выше листингов программы становится очевиден также и ресурс параллелизма алгоритма: каждое одномерное преобразование Фурье выполняется независимо. Самым простым способом использования этого обстоятельства будет вставка соответствующих директив OpenMP перед внутренними циклами - в случае использования многоядерной архтитектуры компьютера на общей памяти. В случае же параллельного выполнения на кластерах с распределенной памятью, необходимо будет позаботиться о распределении входного массива (правой части уравнения) между процессорами, а также &amp;quot;транспозиции&amp;quot; массивов при переходе от БПФ по одному из направлений к БПФ по следующему направлению.&lt;br /&gt;
&lt;br /&gt;
Заметим также, что в приведенной выше реализации для расчета одномерного БПФ производится вызов процедуры библиотеки FFTW, обрабатывающей массив комплексных чисел. В то же время, существует вариант БПФ для преобразования действительных массивов, ускоряющий БПФ в два раза (более подробно см. на [http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data сайте проекта FFTW]).&lt;br /&gt;
&lt;br /&gt;
Важным обстоятельством является то, что большинство вариантов БПФ, включая алгоритм Кули-Тьюки, в арифметике с плавающей запятой имеют очень низкую погрешность.  Верхняя граница относительной ошибки для алгоритма Кули-Тьюки составляет &amp;lt;math&amp;gt;O(\epsilon \log N)&amp;lt;/math&amp;gt; (для сравнения - относительная ошибка преобразования Фурье непосредственно по формуле дискретного преобразования Фурье - &amp;lt;math&amp;gt;O(\epsilon  N^{3/2})&amp;lt;/math&amp;gt;) &amp;lt;ref&amp;gt; Gentleman, W. M.; Sande, G. (1966). &amp;quot;Fast Fourier transforms—for fun and profit&amp;quot;. Proc. AFIPS 29: 563–578. doi:10.1145/1464291.1464352 &amp;lt;/ref&amp;gt;. Поэтому для ускорения алгоритма можно использовать одинарную точность представления переменных без существенного увеличения ошибки.&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
Как было показано выше, существует, по меньшей мере, два уровня параллелизма в описываемом алгоритме. Во-первых, это параллельная реализация одномерных БПФ и, во-вторых, координатный параллелизм - параллельное исполнение независимых одномерных БПФ &amp;lt;ref&amp;gt;Anshu Dubey and Daniele Tessera. Redistribution strategies for portable parallel FFT: a case study. Concurrency and Computation: Practice and Experience, 13(3):209–220, 2001.&amp;lt;/ref&amp;gt;. Эти два уровня могут быть скомбинированы, например, путем распределения разных БПФ между MPI-процессами, а каждого отдельного БПФ - между нитями на общей памяти (POSIX, OpenMP, и т.д.). Ниже мы приведем детали базового алгоритма распараллеливания с использованием координатного параллелизма, рассмотрим его недостатки и перечислим возможные способы повышения его масштабируемости.&lt;br /&gt;
&lt;br /&gt;
Координатный параллелизм в контексте данной задачи реализуется в результате разбиения трехмерной области на подобласти, в каждой из которых можно независимо от расчетов в других подобластях, выполнить одномерные БПФ. К настоящему времени предложены две реализации такого подхода: одномерное разбиение области (slab decomposition) и двумерное разбиение (pencil decomposition) &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;. При одномерном разбиении требуется меньшее количество MPI-пересылок, однако, максимальное количество процессоров/ядер ограничено максимальным по трем измерениям размером области. Поэтому с точки зрения массивного параллелизма двумерная декомпозиция предпочтительнее, и ниже мы остановимся на этом подходе.&lt;br /&gt;
&lt;br /&gt;
При MPI-реализации необходимо принять во внимание накладные расходы, вызванные пересылками данных между процессорами. Для реализации обсуждаемого алгоритма необходимо осуществлять т.н. транспонирования массивов, при которых на каждом из трех этапов преобразования Фурье (этапы 1-3 и 5-7 в п.1.5) обеспечивается нахождение элементов массива вдоль соответствующих направлений в памяти соответствующих процессоров:&lt;br /&gt;
&lt;br /&gt;
[[File:transp.png|center|thumb|800px|Транспонирование трехмерного массива при параллельной реализации трехмерного БПФ]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим соотношение вычислений и пересылок данных при MPI-реализации. Вычислительная сложность алгоритма при покоординатном распараллеливании, при запуске на &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; MPI-процессах составляет  &amp;lt;math&amp;gt; \left(6N^3(\log_2 N) + N^3\right)/M&amp;lt;/math&amp;gt;, т.е., в лучшем случае, &amp;lt;math&amp;gt; 6N(\log_2 N) + N&amp;lt;/math&amp;gt; (на &amp;lt;math&amp;gt;N^2&amp;lt;/math&amp;gt; процессах). При этом, суммарное количество отсылаемых и получаемых MPI-пакетов составляет &amp;lt;math&amp;gt;8N_{px}+4N_{py}&amp;lt;/math&amp;gt;, а суммарное количество отсылаемых и получаемых элементов массива на каждом процессе - &amp;lt;math&amp;gt;12N^3/(N_{px}N_{py})&amp;lt;/math&amp;gt; (здесь - &amp;lt;math&amp;gt;N_{px},~N_{py}&amp;lt;/math&amp;gt; - количества процессов в двумерной MPI-декомпозиции области по осям &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt;, соответственно - см. рис. выше). Учитывая, что &amp;lt;math&amp;gt;M=N_{px}N_{py}&amp;lt;/math&amp;gt;, получаем, что отношение количества пересылаемых элементов массива к количеству арифметических операций составляет &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N + 1)&amp;lt;/math&amp;gt;. Таким образом, отношение объема пересылаемых элементов к количеству операций не зависит от количества MPI-процессов и уменьшается с ростом размера задачи. При больших &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, однако, эта зависимость становится слабой, т.е. &amp;quot;насыщается&amp;quot;. В то же время, при фиксированном размере задачи, рост количества используемых процессов, не изменяя параметра &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;, вызывает рост числа пакетов (&amp;lt;math&amp;gt;\propto \sqrt{M}&amp;lt;/math&amp;gt;, в силу &amp;lt;math&amp;gt;N_{px} \propto N_{py} \propto \sqrt{M}&amp;lt;/math&amp;gt; и формул, приведенных выше). В силу латентности сети, это приводит к росту времени пересылки единицы данных и, следовательно, замедлению ускорения алгоритма. &lt;br /&gt;
&lt;br /&gt;
Приведенный здесь анализ может служить только для ориентировочных оценок, поскольку он не дает времен вычислений и MPI-обменов. Более детальные расчеты для случаев одномерной и двумерной декомпозиции области обширно представлены в литературе &amp;lt;ref&amp;gt;Orlando Ayala, Lian-Ping Wang, Parallel implementation and scalability analysis of 3D Fast Fourier Transform using 2D domain decomposition, Parallel Computing, Volume 39, Issue 1, January 2013, Pages 58-77, ISSN 0167-8191, http://dx.doi.org/10.1016/j.parco.2012.12.002.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;P. Dmitruk, L.-P. Wang, W.H. Matthaeus, R. Zhang, D. Seckel, Scalable parallel FFT for spectral simulations on a Beowulf cluster, Parallel Comput. 27&lt;br /&gt;
(2001) 1921–1936.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В профилируемом в следующих разделах программном коде параллельной реализации алгоритма вызовы одномерных БПФ по трем направлениям, показанные в листинге п.2.1, перемежаются вызовами специальных процедур, осуществляющих транспонирование массива. Отдельно транспонируются действительная и мнимая части массива (что уже не оптимально - лучше пересылать комплексные числа) с помощью коммуникаций &amp;quot;точка-точка&amp;quot;. При этом используются асинхронные пересылки с помощью MPI_ISEND и MPI_IRECV.&lt;br /&gt;
&lt;br /&gt;
=== Результаты прогонов ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Законченные статьи]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_PFFT&amp;diff=29242</id>
		<title>Poisson equation, solving with DFT, PFFT</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_PFFT&amp;diff=29242"/>
		<updated>2022-07-21T12:52:49Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: V.M.Stepanenko, :Ru:Участник:Evg...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[:Ru:Участник:Виктор Степаненко|V.M.Stepanenko]], [[:Ru:Участник:Evgeny Mortikov|E.V.Mortikov]].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Реализация&lt;br /&gt;
! Разбиение области&lt;br /&gt;
! Технологии распараллеливания&lt;br /&gt;
! Обмены в MPI&lt;br /&gt;
|-&lt;br /&gt;
| [https://www-user.tu-chemnitz.de/~potts/workgroup/pippig/software.php.en PFFT]&lt;br /&gt;
| &lt;br /&gt;
| MPI&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;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT, PFFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_MKL_FFT&amp;diff=29241</id>
		<title>Poisson equation, solving with DFT, MKL FFT</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_MKL_FFT&amp;diff=29241"/>
		<updated>2022-07-21T12:49:48Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: V.M.Stepanenko, :Ru:Участник:Evg...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[:Ru:Участник:Виктор Степаненко|V.M.Stepanenko]], [[:Ru:Участник:Evgeny Mortikov|E.V.Mortikov]].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Реализация&lt;br /&gt;
! Разбиение области&lt;br /&gt;
! Технологии распараллеливания&lt;br /&gt;
! Обмены в MPI&lt;br /&gt;
|-&lt;br /&gt;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI&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;
== Масштабируемость алгоритма ==&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT, MKL FFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_AccFFT&amp;diff=29240</id>
		<title>Poisson equation, solving with DFT, AccFFT</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_AccFFT&amp;diff=29240"/>
		<updated>2022-07-21T12:45:23Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: V.M.Stepanenko, :Ru:Участник:Evg...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[:Ru:Участник:Виктор Степаненко|V.M.Stepanenko]], [[:Ru:Участник:Evgeny Mortikov|E.V.Mortikov]].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Реализация&lt;br /&gt;
! Разбиение области&lt;br /&gt;
! Технологии распараллеливания&lt;br /&gt;
! Обмены в MPI&lt;br /&gt;
|-&lt;br /&gt;
| [http://accfft.org/ AccFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&lt;br /&gt;
| MPI, CUDA&lt;br /&gt;
| MPI_ALLTOALL&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;
== Масштабируемость алгоритма ==&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT, AccFFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_cuFFT&amp;diff=29239</id>
		<title>Poisson equation, solving with DFT, cuFFT</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_cuFFT&amp;diff=29239"/>
		<updated>2022-07-21T12:42:10Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: V.M.Stepanenko, :Ru:Участник:Evg...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[:Ru:Участник:Виктор Степаненко|V.M.Stepanenko]], [[:Ru:Участник:Evgeny Mortikov|E.V.Mortikov]].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Реализация&lt;br /&gt;
! Разбиение области&lt;br /&gt;
! Технологии распараллеливания&lt;br /&gt;
! Обмены в MPI&lt;br /&gt;
|-&lt;br /&gt;
| [http://docs.nvidia.com/cuda/cufft/#axzz3tAvWIMTp cuFFT]&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;
=== Количественная оценка локальности ===&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;
[[En:Poisson equation, solving with DFT, cuFFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_P3DFFT&amp;diff=29238</id>
		<title>Poisson equation, solving with DFT, P3DFFT</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_P3DFFT&amp;diff=29238"/>
		<updated>2022-07-21T12:38:56Z</updated>

		<summary type="html">&lt;p&gt;ASA: Новая страница: «{{level-i}}  Основные авторы описания: V.M.Stepanenko, :Ru:Участник:Evg...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[:Ru:Участник:Виктор Степаненко|V.M.Stepanenko]], [[:Ru:Участник:Evgeny Mortikov|E.V.Mortikov]].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Реализация&lt;br /&gt;
! Разбиение области&lt;br /&gt;
! Технологии распараллеливания&lt;br /&gt;
! Обмены в MPI&lt;br /&gt;
|-&lt;br /&gt;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&lt;br /&gt;
| MPI&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;
== Масштабируемость алгоритма ==&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT, P3DFFT]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_FFTE&amp;diff=29237</id>
		<title>Poisson equation, solving with DFT, FFTE</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Poisson_equation,_solving_with_DFT,_FFTE&amp;diff=29237"/>
		<updated>2022-07-21T12:28:09Z</updated>

		<summary type="html">&lt;p&gt;ASA: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-i}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[:Ru:Участник:Виктор Степаненко|V.M.Stepanenko]], [[:Ru:Участник:Evgeny Mortikov|E.V.Mortikov]].&lt;br /&gt;
&lt;br /&gt;
= Ссылки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Реализация&lt;br /&gt;
! Разбиение области&lt;br /&gt;
! Технологии распараллеливания&lt;br /&gt;
! Обмены в MPI&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.ffte.jp/ FFTE]&lt;br /&gt;
| 1D &amp;amp; 2D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| MPI_ALLTOALL&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;
== Масштабируемость алгоритма ==&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
= Динамические характеристики и эффективность реализации алгоритма =&lt;br /&gt;
= Результаты прогонов =&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
&lt;br /&gt;
[[En:Poisson equation, solving with DFT, FFTE]]&lt;/div&gt;</summary>
		<author><name>ASA</name></author>
	</entry>
</feed>