<?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=%D0%98%D0%BA%D1%80%D0%B0%D0%BC%D0%BE%D0%B2</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=%D0%98%D0%BA%D1%80%D0%B0%D0%BC%D0%BE%D0%B2"/>
	<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/%D0%98%D0%BA%D1%80%D0%B0%D0%BC%D0%BE%D0%B2"/>
	<updated>2026-10-22T14:20:46Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3442</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3442"/>
		<updated>2016-04-09T16:11:30Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Search algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary search: Finding the position of a target value within a sorted array}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Sorting algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary tree sort}}&lt;br /&gt;
## {{level|Bubble sort}}&lt;br /&gt;
## {{level|Merge sort (serial and parallel variants)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Computational geometry&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Finding the diameter of a point set}}&lt;br /&gt;
## {{level|Finding the convex hull of a point set}}&lt;br /&gt;
## {{level|Delaunay triangulation}}&lt;br /&gt;
## {{level|Voronoi diagram}}&lt;br /&gt;
## {{level|Point-in-polygon problem}}&lt;br /&gt;
## {{level|Convex polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Star-shaped polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Computer graphics&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Line drawing algorithms: Approximating a line segment on discrete graphical media}}&lt;br /&gt;
## {{level|Determining visible parts of a three-dimensional scene}}&lt;br /&gt;
## {{level|Ray tracing: Rendering realistic images}}&lt;br /&gt;
## {{level|Global illumination: Regarding direct illumination and reflection from other objects}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Cryptographic algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Neural networks&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Optimization algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Linear programming}}&lt;br /&gt;
## {{level|Simplex algorithm}}&lt;br /&gt;
## {{level|Branch and bound method (serial and parallel variants)}}&lt;br /&gt;
## {{level|Genetic algorithms}}&lt;br /&gt;
## {{level|Ant colony algorithms}}&lt;br /&gt;
## {{level|Hybrid algorithms}}&lt;br /&gt;
## {{level|Finding extrema of a function}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Game theory algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Algorithms for quantum system simulation&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Algorithms for quantum computation simulation&#039;&#039;&lt;br /&gt;
### {{level|Single-qubit transform of a state vector}}&lt;br /&gt;
### {{level|Two-qubit transform of a state vector}}&lt;br /&gt;
### {{level|Quantum Fourier transform simulation}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Algorithms for solving equations of mathematical physics&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Poisson equation: Solving with DFT}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Other algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3441</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3441"/>
		<updated>2016-04-09T16:06:30Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Search algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary search: Finding the position of a target value within a sorted array}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Sorting algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary tree sort}}&lt;br /&gt;
## {{level|Bubble sort}}&lt;br /&gt;
## {{level|Merge sort (serial and parallel variants)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Computational geometry&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Finding the diameter of a point set}}&lt;br /&gt;
## {{level|Finding the convex hull of a point set}}&lt;br /&gt;
## {{level|Delaunay triangulation}}&lt;br /&gt;
## {{level|Voronoi diagram}}&lt;br /&gt;
## {{level|Point-in-polygon problem}}&lt;br /&gt;
## {{level|Convex polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Star-shaped polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Computer graphics&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Line drawing algorithms: Approximating a line segment on discrete graphical media}}&lt;br /&gt;
## {{level|Determining visible parts of a three-dimensional scene}}&lt;br /&gt;
## {{level|Ray tracing: Rendering realistic images}}&lt;br /&gt;
## {{level|Global illumination: Regarding direct illumination and reflection from other objects}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Cryptographic algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Neural networks&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Optimization algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Linear programming}}&lt;br /&gt;
## {{level|Simplex algorithm}}&lt;br /&gt;
## {{level|Branch and bound method (serial and parallel variants)}}&lt;br /&gt;
## {{level|Genetic algorithms}}&lt;br /&gt;
## {{level|Ant colony algorithms}}&lt;br /&gt;
## {{level|Hybrid algorithms}}&lt;br /&gt;
## {{level|Finding extrema of a function}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Game theory algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Algorithms for quantum system simulation&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Algorithms for quantum computation simulation&#039;&#039;&lt;br /&gt;
### {{level|Single-qubit transform of a state vector}}&lt;br /&gt;
### {{level|Two-qubit transform of a state vector}}&lt;br /&gt;
### {{level|Quantum Fourier transform simulation}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3440</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3440"/>
		<updated>2016-04-09T15:44:29Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Search algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary search: Finding the position of a target value within a sorted array}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Sorting algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary tree sort}}&lt;br /&gt;
## {{level|Bubble sort}}&lt;br /&gt;
## {{level|Merge sort (serial and parallel variants)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Computational geometry&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Finding the diameter of a point set}}&lt;br /&gt;
## {{level|Finding the convex hull of a point set}}&lt;br /&gt;
## {{level|Delaunay triangulation}}&lt;br /&gt;
## {{level|Voronoi diagram}}&lt;br /&gt;
## {{level|Point-in-polygon problem}}&lt;br /&gt;
## {{level|Convex polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Star-shaped polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Computer graphics&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Line drawing algorithms: Approximating a line segment on discrete graphical media}}&lt;br /&gt;
## {{level|Determining visible parts of a three-dimensional scene}}&lt;br /&gt;
## {{level|Ray tracing: Rendering realistic images}}&lt;br /&gt;
## {{level|Global illumination: Regarding direct illumination and reflection from other objects}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Cryptographic algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Neural networks&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Optimization algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Linear programming}}&lt;br /&gt;
## {{level|Simplex algorithm}}&lt;br /&gt;
## {{level|Branch and bound method (serial and parallel variants)}}&lt;br /&gt;
## {{level|Genetic algorithms}}&lt;br /&gt;
## {{level|Ant colony algorithms}}&lt;br /&gt;
## {{level|Hybrid algorithms}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3439</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3439"/>
		<updated>2016-04-09T15:17:26Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Search algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary search: Finding the position of a target value within a sorted array}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Sorting algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary tree sort}}&lt;br /&gt;
## {{level|Bubble sort}}&lt;br /&gt;
## {{level|Merge sort (serial and parallel variants)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Computational geometry&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Finding the diameter of a point set}}&lt;br /&gt;
## {{level|Finding the convex hull of a point set}}&lt;br /&gt;
## {{level|Delaunay triangulation}}&lt;br /&gt;
## {{level|Voronoi diagram}}&lt;br /&gt;
## {{level|Point-in-polygon problem}}&lt;br /&gt;
## {{level|Convex polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Star-shaped polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Computer graphics&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Line drawing algorithms: Approximating a line segment on discrete graphical media}}&lt;br /&gt;
## {{level|Determining visible parts of a three-dimensional scene}}&lt;br /&gt;
## {{level|Ray tracing: Rendering realistic images}}&lt;br /&gt;
## {{level|Global illumination: Regarding direct illumination and reflection from other objects}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3438</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3438"/>
		<updated>2016-04-09T14:12:31Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Search algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary search: Finding the position of a target value within a sorted array}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Sorting algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary tree sort}}&lt;br /&gt;
## {{level|Bubble sort}}&lt;br /&gt;
## {{level|Merge sort (serial and parallel variants)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Computational geometry&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Finding the diameter of a point set}}&lt;br /&gt;
## {{level|Finding the convex hull of a point set}}&lt;br /&gt;
## {{level|Delaunay triangulation}}&lt;br /&gt;
## {{level|Voronoi diagram}}&lt;br /&gt;
## {{level|Point-in-polygon problem}}&lt;br /&gt;
## {{level|Convex polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Star-shaped polygon intersection}} - complexity &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3437</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3437"/>
		<updated>2016-04-09T12:47:35Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Search algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary search: Finding the position of a target value within a sorted array}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Sorting algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Binary tree sort}}&lt;br /&gt;
## {{level|Bubble sort}}&lt;br /&gt;
## {{level|Merge sort (serial and parallel variants)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3436</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3436"/>
		<updated>2016-04-09T12:23:46Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Shiloach-Vishkin algorithm for finding the connected components}}&lt;br /&gt;
### {{level|Disjoint set union}}&lt;br /&gt;
### {{level|Tarjan&#039;s strongly connected components algorithm}}&lt;br /&gt;
### {{level|DCSC algorithm for finding the strongly connected components}}&lt;br /&gt;
### {{level|Tarjan&#039;s biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan-Vishkin biconnected components algorithm}}&lt;br /&gt;
### {{level|Tarjan&#039;s algorithm for finding the bridges of a graph}}&lt;br /&gt;
### {{level|Vertex connectivity of a graph}}&lt;br /&gt;
### {{level|Gabow&#039;s edge connectivity algorithm}}&lt;br /&gt;
## {{level|Finding maximal flow in a transportation network}}&lt;br /&gt;
### {{level|Ford–Fulkerson algorithm}}&lt;br /&gt;
### {{level|Preflow-Push algorithm}}&lt;br /&gt;
## {{level|Finding minimal-cost flow in a transportation network}}&lt;br /&gt;
## {{level|Assignment problem}}&lt;br /&gt;
### {{level|Hungarian algorithm}}&lt;br /&gt;
### {{level|Auction algorithm}}&lt;br /&gt;
### {{level|Hopcroft–Karp algorithm}}&lt;br /&gt;
## {{level|Betweenness centrality algorithm|Finding the betweenness centrality of vertices}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3435</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3435"/>
		<updated>2016-04-09T11:27:51Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Boruvka&#039;s akgorithm}}&lt;br /&gt;
### {{level|Kruskal&#039;s algorithm}}&lt;br /&gt;
### {{level|Prim&#039;s algorithm}}&lt;br /&gt;
### {{level|GHS algorithm}}&lt;br /&gt;
## {{level|Search for isomorphic subgraphs}}&lt;br /&gt;
### {{level|Ullman&#039;s algorithm}}&lt;br /&gt;
### {{level|VF2 algorithm}}&lt;br /&gt;
## {{level|Graph connectivity}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3434</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3434"/>
		<updated>2016-04-09T11:13:59Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Single source shortest path (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|All pairs shortest path (APSP)}}&lt;br /&gt;
### {{level|Johnson&#039;s algorithm}}&lt;br /&gt;
### {{level|Floyd-Warshall algorithm}}&lt;br /&gt;
## {{level|Transitive closure of a directed graph}}&lt;br /&gt;
### {{level|Purdom&#039;s algorithm}}&lt;br /&gt;
## {{level|Longest shortest path}}&lt;br /&gt;
## {{level|Construction of the minimum spanning tree (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3433</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3433"/>
		<updated>2016-04-09T10:52:00Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Graph algorithms&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Traversing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Search for a shortest path from a vertex (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Δ-stepping algorithm}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3432</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3432"/>
		<updated>2016-04-08T20:36:45Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Algorithms on graphs&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Bypassing a graph &lt;br /&gt;
### {{level|Breadth-first search (BFS)}}&lt;br /&gt;
### {{level|Depth-first search (DFS)}}&lt;br /&gt;
## {{level|Search for a shortest path from a vertex (SSSP)}}&lt;br /&gt;
### {{level|Breadth-first search (BFS)}} (for unweighted graphs)&lt;br /&gt;
### {{level|Dijkstra&#039;s algorithm}}&lt;br /&gt;
### {{level|Bellman-Ford algorithm}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3431</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3431"/>
		<updated>2016-04-08T20:04:08Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss rules}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3430</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3430"/>
		<updated>2016-04-08T19:54:16Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Rectangle rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Trapezoid rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description |Simpson rule}}&lt;br /&gt;
### {{level|Numerical quadrature (cubature) rules on an interval (for a multidimensional cube)#Mathematical description|Gauss }}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3429</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3429"/>
		<updated>2016-04-08T19:24:45Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Fast Fourier transform for powers of two}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Algebra of polynomials&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Horner&#039;s rule: Real version, serial variant|Horner&#039;s rule}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Numerical quadrature&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Cubature rules}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3428</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3428"/>
		<updated>2016-04-08T19:19:45Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Fourier transform&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3427</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3427"/>
		<updated>2016-04-08T15:52:19Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for matrices of special form}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving block SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Two-sided Thomas algorithm, block variant}}&lt;br /&gt;
###### {{level|Block cyclic reduction}}&lt;br /&gt;
###### {{level|Block bordering method}}&lt;br /&gt;
### {{level|Solving SLAEs with coefficient matrices of special form whose inverses are known}}&lt;br /&gt;
## Iterative methods for solving SLAEs &lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Solving eigenvalue problems&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|QR algorithm}}&lt;br /&gt;
### {{level|Givens method (rotation method) for solving the symmetric eigenvalue problem}}&lt;br /&gt;
## {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Computer performance tests&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3426</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3426"/>
		<updated>2016-04-08T15:27:44Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for special matrices}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving tridiagonal SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Complete cyclic reduction}}&lt;br /&gt;
####### {{level|Cyclic reduction repeated for a new right-hand side}}&lt;br /&gt;
###### {{level|Bordering method}}&lt;br /&gt;
#### Methods for solving block triangular SLAEs &lt;br /&gt;
##### {{level|Block forward substitution (real version)|Block forward substitution}}&lt;br /&gt;
##### {{level|Block backward substitution (real version))|Block backward substitution}}&lt;br /&gt;
##### Methods for solving block bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving block bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the block backward substitution for solving block bidiagonal SLAEs}}&lt;br /&gt;
#### {{level|Methods for solving block tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Block Thomas algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving triangular SLAEs based on the LU decomposition and backward substitutions Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3425</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3425"/>
		<updated>2016-04-08T14:52:53Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for special matrices}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs of special forms &lt;br /&gt;
#### Methods for solving triangular SLAEs  &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving bidiagonal SLAEs &lt;br /&gt;
###### {{level|Forward and backward substitution for bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Stone doubling algorithm for solving bidiagonal SLAEs}}&lt;br /&gt;
###### {{level|Serial-parallel variant of the backward substitution}}&lt;br /&gt;
#### {{level|Methods for solving tridiagonal SLAEs}}&lt;br /&gt;
##### Methods based on the conventional LU decomposition &lt;br /&gt;
###### {{level|Thomas algorithm}}&lt;br /&gt;
####### {{level|Thomas algorithm, pointwise version|Classical monotone elimination algorithm}}&lt;br /&gt;
####### {{level|Repeated Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Classical scheme}}&lt;br /&gt;
###### {{level|Stone doubling algorithm}}&lt;br /&gt;
###### {{level|Serial-parallel method for solving triangular SLAEs based on the LU decomposition and backward substitutions}}&lt;br /&gt;
##### Other methods &lt;br /&gt;
###### {{level|Reduction method}}&lt;br /&gt;
####### {{level|Complete reduction method}}&lt;br /&gt;
####### {{level|Reduction method repeated for a new right-hand side}}&lt;br /&gt;
###### Two-sided Thomas algorithm &lt;br /&gt;
####### {{level|Two-sided Thomas algorithm, pointwise version|Classical two-sided scheme}}&lt;br /&gt;
####### {{level|Repeated two-sided Thomas algorithm, pointwise version|Thomas algorithm repeated for a new right-hand side: Two-sided scheme }}&lt;br /&gt;
###### {{level|Cyclic reduction}}&lt;br /&gt;
####### {{level|Полный метод циклической редукции}}&lt;br /&gt;
####### {{level|Повторный метод циклической редукции для новой правой части}}&lt;br /&gt;
###### {{level|Метод окаймления}}&lt;br /&gt;
#### Методы решения СЛАУ с блочно-треугольными матрицами&lt;br /&gt;
##### {{level|Блочная прямая подстановка (вещественный вариант)|Блочная прямая подстановка}}&lt;br /&gt;
##### {{level|Блочная обратная подстановка (вещественный вариант)|Блочная обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с блочно-двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с блочно-двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант обратной подстановки для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с блочно-трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Блочная прогонка}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3424</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3424"/>
		<updated>2016-04-08T13:37:06Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}}: Basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for special matrices}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs with coefficient matrices of a special form &lt;br /&gt;
#### Methods for solving SLAEs with triangular coefficient matrices &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving SLAEs with bidiagonal coefficient matrices &lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант обратной подстановки}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Прогонка}}&lt;br /&gt;
####### {{level|Прогонка, точечный вариант|Классическая монотонная прогонка}}&lt;br /&gt;
####### {{level|Повторная прогонка, точечный вариант|Повторная прогонка для новой правой части, классическая схема}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Метод редукции}}&lt;br /&gt;
####### {{level|Полный метод редукции}}&lt;br /&gt;
####### {{level|Повторный метод редукции для новой правой части}}&lt;br /&gt;
###### Встречная прогонка&lt;br /&gt;
####### {{level|Встречная прогонка, точечный вариант|Классическая встречная прогонка}}&lt;br /&gt;
####### {{level|Повторная встречная прогонка, точечный вариант|Повторная прогонка для новой правой части, встречная схема}}&lt;br /&gt;
###### {{level|Метод циклической редукции}}&lt;br /&gt;
####### {{level|Полный метод циклической редукции}}&lt;br /&gt;
####### {{level|Повторный метод циклической редукции для новой правой части}}&lt;br /&gt;
###### {{level|Метод окаймления}}&lt;br /&gt;
#### Методы решения СЛАУ с блочно-треугольными матрицами&lt;br /&gt;
##### {{level|Блочная прямая подстановка (вещественный вариант)|Блочная прямая подстановка}}&lt;br /&gt;
##### {{level|Блочная обратная подстановка (вещественный вариант)|Блочная обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с блочно-двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с блочно-двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант обратной подстановки для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с блочно-трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Блочная прогонка}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3423</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3423"/>
		<updated>2016-04-08T13:31:31Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}} basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for special matrices}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Householder method (reflection method) for the QR-decomposition of a matrix}}&lt;br /&gt;
## &#039;&#039;Unitary Hessenberg decompositions&#039;&#039;&lt;br /&gt;
### {{level|Householder method (reflection method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
### {{level|Givens method (rotation method) for reducing a matrix to Hessenberg (bidiagonal) form}}&lt;br /&gt;
## &#039;&#039;Unitary-diagonal decompositions&#039;&#039;&lt;br /&gt;
### {{level|Eigenvalue decomposition (finding eigenvalues and eigenvectors)}}&lt;br /&gt;
### {{level|Singular value decomposition (finding singular values and singular vectors)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Solving systems of linear algebraic equations (SLAEs)&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Direct methods for solving SLAEs &lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Methods for solving SLAEs with coefficient matrices of a special form &lt;br /&gt;
#### Methods for solving SLAEs with triangular coefficient matrices &lt;br /&gt;
##### {{level|Forward substitution (real version)|Forward substitution}}&lt;br /&gt;
##### {{level|Backward substitution (real version)|Backward substitution}}&lt;br /&gt;
##### Methods for solving SLAEs with bidiagonal coefficient matrices &lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант обратной подстановки}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Прогонка}}&lt;br /&gt;
####### {{level|Прогонка, точечный вариант|Классическая монотонная прогонка}}&lt;br /&gt;
####### {{level|Повторная прогонка, точечный вариант|Повторная прогонка для новой правой части, классическая схема}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Метод редукции}}&lt;br /&gt;
####### {{level|Полный метод редукции}}&lt;br /&gt;
####### {{level|Повторный метод редукции для новой правой части}}&lt;br /&gt;
###### Встречная прогонка&lt;br /&gt;
####### {{level|Встречная прогонка, точечный вариант|Классическая встречная прогонка}}&lt;br /&gt;
####### {{level|Повторная встречная прогонка, точечный вариант|Повторная прогонка для новой правой части, встречная схема}}&lt;br /&gt;
###### {{level|Метод циклической редукции}}&lt;br /&gt;
####### {{level|Полный метод циклической редукции}}&lt;br /&gt;
####### {{level|Повторный метод циклической редукции для новой правой части}}&lt;br /&gt;
###### {{level|Метод окаймления}}&lt;br /&gt;
#### Методы решения СЛАУ с блочно-треугольными матрицами&lt;br /&gt;
##### {{level|Блочная прямая подстановка (вещественный вариант)|Блочная прямая подстановка}}&lt;br /&gt;
##### {{level|Блочная обратная подстановка (вещественный вариант)|Блочная обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с блочно-двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с блочно-двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант обратной подстановки для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с блочно-трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Блочная прогонка}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3422</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3422"/>
		<updated>2016-04-08T11:57:14Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix decompositions&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}} basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for special matrices}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Метод Хаусхолдера (отражений) QR-разложения матрицы}}&lt;br /&gt;
## &#039;&#039;Разложения на унитарные и хессенберговы матрицы&#039;&#039;&lt;br /&gt;
### {{level|Метод Хаусхолдера (отражений) приведения матрицы к хессенберговой (двухдиагональной) форме}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) приведения матрицы к хессенберговой (двухдиагональной) форме}}&lt;br /&gt;
## &#039;&#039;Разложения на унитарные и диагональные матрицы&#039;&#039;&lt;br /&gt;
### {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Решение систем линейных уравнений&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Прямые методы решения СЛАУ&lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Методы решения СЛАУ с матрицами специального вида&lt;br /&gt;
#### Методы решения СЛАУ с треугольными матрицами&lt;br /&gt;
##### {{level|Прямая подстановка (вещественный вариант)|Прямая подстановка}}&lt;br /&gt;
##### {{level|Обратная подстановка (вещественный вариант)|Обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант обратной подстановки}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Прогонка}}&lt;br /&gt;
####### {{level|Прогонка, точечный вариант|Классическая монотонная прогонка}}&lt;br /&gt;
####### {{level|Повторная прогонка, точечный вариант|Повторная прогонка для новой правой части, классическая схема}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Метод редукции}}&lt;br /&gt;
####### {{level|Полный метод редукции}}&lt;br /&gt;
####### {{level|Повторный метод редукции для новой правой части}}&lt;br /&gt;
###### Встречная прогонка&lt;br /&gt;
####### {{level|Встречная прогонка, точечный вариант|Классическая встречная прогонка}}&lt;br /&gt;
####### {{level|Повторная встречная прогонка, точечный вариант|Повторная прогонка для новой правой части, встречная схема}}&lt;br /&gt;
###### {{level|Метод циклической редукции}}&lt;br /&gt;
####### {{level|Полный метод циклической редукции}}&lt;br /&gt;
####### {{level|Повторный метод циклической редукции для новой правой части}}&lt;br /&gt;
###### {{level|Метод окаймления}}&lt;br /&gt;
#### Методы решения СЛАУ с блочно-треугольными матрицами&lt;br /&gt;
##### {{level|Блочная прямая подстановка (вещественный вариант)|Блочная прямая подстановка}}&lt;br /&gt;
##### {{level|Блочная обратная подстановка (вещественный вариант)|Блочная обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с блочно-двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с блочно-двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант обратной подстановки для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с блочно-трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Блочная прогонка}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3421</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3421"/>
		<updated>2016-04-08T11:56:29Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix factorizations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Gaussian elimination with diagonal pivoting &lt;br /&gt;
##### Gaussian elimination with complete pivoting &lt;br /&gt;
### {{level|Cholesky method (finding the symmetric triangular decomposition)}}&lt;br /&gt;
#### {{level|Cholesky decomposition (square root method)}} basic pointwise real variant, dense symmetric positive definite matrix &lt;br /&gt;
### {{level|Available triangular decompositions for special matrices}}&lt;br /&gt;
## &#039;&#039;Unitary-triangular decompositions&#039;&#039;&lt;br /&gt;
### {{level|Givens method (rotation method) for the QR-decomposition of a matrix}}&lt;br /&gt;
### {{level|Метод Хаусхолдера (отражений) QR-разложения матрицы}}&lt;br /&gt;
## &#039;&#039;Разложения на унитарные и хессенберговы матрицы&#039;&#039;&lt;br /&gt;
### {{level|Метод Хаусхолдера (отражений) приведения матрицы к хессенберговой (двухдиагональной) форме}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) приведения матрицы к хессенберговой (двухдиагональной) форме}}&lt;br /&gt;
## &#039;&#039;Разложения на унитарные и диагональные матрицы&#039;&#039;&lt;br /&gt;
### {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Решение систем линейных уравнений&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Прямые методы решения СЛАУ&lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Методы решения СЛАУ с матрицами специального вида&lt;br /&gt;
#### Методы решения СЛАУ с треугольными матрицами&lt;br /&gt;
##### {{level|Прямая подстановка (вещественный вариант)|Прямая подстановка}}&lt;br /&gt;
##### {{level|Обратная подстановка (вещественный вариант)|Обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант обратной подстановки}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Прогонка}}&lt;br /&gt;
####### {{level|Прогонка, точечный вариант|Классическая монотонная прогонка}}&lt;br /&gt;
####### {{level|Повторная прогонка, точечный вариант|Повторная прогонка для новой правой части, классическая схема}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Метод редукции}}&lt;br /&gt;
####### {{level|Полный метод редукции}}&lt;br /&gt;
####### {{level|Повторный метод редукции для новой правой части}}&lt;br /&gt;
###### Встречная прогонка&lt;br /&gt;
####### {{level|Встречная прогонка, точечный вариант|Классическая встречная прогонка}}&lt;br /&gt;
####### {{level|Повторная встречная прогонка, точечный вариант|Повторная прогонка для новой правой части, встречная схема}}&lt;br /&gt;
###### {{level|Метод циклической редукции}}&lt;br /&gt;
####### {{level|Полный метод циклической редукции}}&lt;br /&gt;
####### {{level|Повторный метод циклической редукции для новой правой части}}&lt;br /&gt;
###### {{level|Метод окаймления}}&lt;br /&gt;
#### Методы решения СЛАУ с блочно-треугольными матрицами&lt;br /&gt;
##### {{level|Блочная прямая подстановка (вещественный вариант)|Блочная прямая подстановка}}&lt;br /&gt;
##### {{level|Блочная обратная подстановка (вещественный вариант)|Блочная обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с блочно-двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с блочно-двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант обратной подстановки для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с блочно-трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Блочная прогонка}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3420</id>
		<title>Algorithm classification</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=Algorithm_classification&amp;diff=3420"/>
		<updated>2016-04-08T11:35:07Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# &amp;lt;div id=&amp;quot;Векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Pairwise summation&#039;&#039;&lt;br /&gt;
### {{level|Summing an array by pairwise summation}}&lt;br /&gt;
### {{level|Finding partial sums of an array by pairwise summation}}&lt;br /&gt;
## {{level|Uniform norm of a vector: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Dot product: Real version, serial-parallel variant}}&lt;br /&gt;
## {{level|Serial-parallel summation method}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матрично-векторные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix-vector operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix-vector multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Матричные операции&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix operations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Dense matrix multiplication}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Разложения матриц&amp;quot;&amp;gt;&#039;&#039;&#039;Matrix factorizations&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Triangular decompositions&#039;&#039;&lt;br /&gt;
### Gaussian elimination (finding the LU decomposition)&lt;br /&gt;
#### {{level|Gaussian elimination without pivoting}}&lt;br /&gt;
##### LU decomposition via Gaussian elimination &lt;br /&gt;
##### Compact scheme for Gaussian elimination and its modifications &lt;br /&gt;
###### Compact scheme for Gaussian elimination: Dense matrix &lt;br /&gt;
###### {{level|Compact scheme for Gaussian elimination and its modifications: Tridiagonal matrix}}&lt;br /&gt;
####### {{level|Compact scheme for Gaussian elimination: Tridiagonal matrix, serial variant}}&lt;br /&gt;
####### {{level|Stone doubling algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
####### {{level|Serial-parallel algorithm for the LU decomposition of a tridiagonal matrix}}&lt;br /&gt;
#### Gaussian elimination with pivoting &lt;br /&gt;
##### Gaussian elimination with column pivoting &lt;br /&gt;
##### Gaussian elimination with row pivoting &lt;br /&gt;
##### Метод Гаусса с выбором ведущего элемента по главной диагонали&lt;br /&gt;
##### Метод Гаусса с выбором ведущего элемента по всей матрице&lt;br /&gt;
### {{level|Метод Холецкого (нахождение симметричного треугольного разложения)}}&lt;br /&gt;
#### {{level|Разложение Холецкого (метод квадратного корня)}} базовый точечный вещественный вариант для плотной симметричной положительно-определённой матрицы&lt;br /&gt;
### {{level|Известные треугольные разложения для матриц специального вида}}&lt;br /&gt;
## &#039;&#039;Унитарно-треугольные разложения&#039;&#039;&lt;br /&gt;
### {{level|Метод Гивенса (вращений) QR-разложения матрицы}}&lt;br /&gt;
### {{level|Метод Хаусхолдера (отражений) QR-разложения матрицы}}&lt;br /&gt;
## &#039;&#039;Разложения на унитарные и хессенберговы матрицы&#039;&#039;&lt;br /&gt;
### {{level|Метод Хаусхолдера (отражений) приведения матрицы к хессенберговой (двухдиагональной) форме}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) приведения матрицы к хессенберговой (двухдиагональной) форме}}&lt;br /&gt;
## &#039;&#039;Разложения на унитарные и диагональные матрицы&#039;&#039;&lt;br /&gt;
### {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решение систем линейных уравнений&amp;quot;&amp;gt;&#039;&#039;&#039;Решение систем линейных уравнений&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Прямые методы решения СЛАУ&lt;br /&gt;
### {{level|Linpack benchmark}}&lt;br /&gt;
### Методы решения СЛАУ с матрицами специального вида&lt;br /&gt;
#### Методы решения СЛАУ с треугольными матрицами&lt;br /&gt;
##### {{level|Прямая подстановка (вещественный вариант)|Прямая подстановка}}&lt;br /&gt;
##### {{level|Обратная подстановка (вещественный вариант)|Обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант обратной подстановки}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Прогонка}}&lt;br /&gt;
####### {{level|Прогонка, точечный вариант|Классическая монотонная прогонка}}&lt;br /&gt;
####### {{level|Повторная прогонка, точечный вариант|Повторная прогонка для новой правой части, классическая схема}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна}}&lt;br /&gt;
###### {{level|Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Метод редукции}}&lt;br /&gt;
####### {{level|Полный метод редукции}}&lt;br /&gt;
####### {{level|Повторный метод редукции для новой правой части}}&lt;br /&gt;
###### Встречная прогонка&lt;br /&gt;
####### {{level|Встречная прогонка, точечный вариант|Классическая встречная прогонка}}&lt;br /&gt;
####### {{level|Повторная встречная прогонка, точечный вариант|Повторная прогонка для новой правой части, встречная схема}}&lt;br /&gt;
###### {{level|Метод циклической редукции}}&lt;br /&gt;
####### {{level|Полный метод циклической редукции}}&lt;br /&gt;
####### {{level|Повторный метод циклической редукции для новой правой части}}&lt;br /&gt;
###### {{level|Метод окаймления}}&lt;br /&gt;
#### Методы решения СЛАУ с блочно-треугольными матрицами&lt;br /&gt;
##### {{level|Блочная прямая подстановка (вещественный вариант)|Блочная прямая подстановка}}&lt;br /&gt;
##### {{level|Блочная обратная подстановка (вещественный вариант)|Блочная обратная подстановка}}&lt;br /&gt;
##### Методы решения СЛАУ с блочно-двухдиагональными матрицами&lt;br /&gt;
###### {{level|Прямая и обратная подстановка в СЛАУ с блочно-двухдиагональной матрицей}}&lt;br /&gt;
###### {{level|Метод сдваивания Стоуна для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант обратной подстановки для решения блочно-двухдиагональных СЛАУ}}&lt;br /&gt;
#### {{level|Методы решения СЛАУ с блочно-трёхдиагональными матрицами}}&lt;br /&gt;
##### Методы, основанные на стандартном LU-разложении матрицы&lt;br /&gt;
###### {{level|Блочная прогонка}}&lt;br /&gt;
###### {{level|Блочный последовательно-параллельный вариант решения с LU-разложением и обратными подстановками}}&lt;br /&gt;
##### Другие методы&lt;br /&gt;
###### {{level|Встречная прогонка, блочный вариант}}&lt;br /&gt;
###### {{level|Блочный метод циклической редукции}}&lt;br /&gt;
###### {{level|Блочный метод окаймления}}&lt;br /&gt;
### {{level|Решения СЛАУ с матрицами специального вида, имеющими известные обратные матрицы}}&lt;br /&gt;
## Итерационные методы решения СЛАУ&lt;br /&gt;
### {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Решения спектральных задач&amp;quot;&amp;gt;&#039;&#039;&#039;Решения спектральных задач&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Спектральное разложение (нахождение собственных значений и векторов)}}&lt;br /&gt;
### {{level|QR-алгоритм}}&lt;br /&gt;
### {{level|Метод Гивенса (вращений) для решения спектральной задачи у симметричных матриц}}&lt;br /&gt;
## {{level|Сингулярное разложение (нахождение сингулярных значений и векторов)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Тесты производительности компьютеров&amp;quot;&amp;gt;&#039;&#039;&#039;Тесты производительности компьютеров&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|High Performance Conjugate Gradient (HPCG) benchmark}}&lt;br /&gt;
## {{level|Linpack benchmark}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Преобразование Фурье&amp;quot;&amp;gt;&#039;&#039;&#039;Преобразование Фурье&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Быстрое преобразование Фурье для степеней двойки}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгебра многочленов&amp;quot;&amp;gt;&#039;&#039;&#039;Алгебра многочленов&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Схема Горнера, вещественная версия, последовательный вариант|Схема Горнера}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Численные методы интегрирования&amp;quot;&amp;gt;&#039;&#039;&#039;Численные методы интегрирования&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Квадратурные формулы}}&lt;br /&gt;
## {{level|Квадратурные (кубатурные) методы численного интегрирования по отрезку (многомерному кубу)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод прямоугольников}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод трапеций}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод парабол (метод Симпсона)}}&lt;br /&gt;
### {{level|Квадратурные_(кубатурные)_методы_численного_интегрирования_по_отрезку_(многомерному_кубу)#Математическое описание|Метод Гаусса}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы на графах&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы на графах&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## Обход графа&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}}&lt;br /&gt;
### {{level|Поиск в глубину (DFS)}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути от одной вершины (SSSP)}}&lt;br /&gt;
### {{level|Поиск в ширину (BFS)}} (для невзвешенных графов)&lt;br /&gt;
### {{level|Алгоритм Дейкстры}}&lt;br /&gt;
### {{level|Алгоритм Беллмана-Форда}}&lt;br /&gt;
### {{level|Алгоритм Δ-шагания}}&lt;br /&gt;
## {{level|Поиск кратчайшего пути для всех пар вершин (APSP)}}&lt;br /&gt;
### {{level|Алгоритм Джонсона}}&lt;br /&gt;
### {{level|Алгоритм Флойда-Уоршелла}}&lt;br /&gt;
## {{level|Поиск транзитивного замыкания орграфа}}&lt;br /&gt;
### {{level|Алгоритм Пурдома}}&lt;br /&gt;
## {{level|Определение диаметра графа}}&lt;br /&gt;
## {{level|Построение минимального остовного дерева (MST)}}&lt;br /&gt;
### {{level|Алгоритм Борувки}}&lt;br /&gt;
### {{level|Алгоритм Крускала}}&lt;br /&gt;
### {{level|Алгоритм Прима}}&lt;br /&gt;
### {{level|Алгоритм GHS}}&lt;br /&gt;
## {{level|Поиск изоморфных подграфов}}&lt;br /&gt;
### {{level|Алгоритм Ульмана}}&lt;br /&gt;
### {{level|Алгоритм VF2}}&lt;br /&gt;
## {{level|Связность в графах}}&lt;br /&gt;
### {{level|Алгоритм Шилоаха-Вишкина поиска компонент связности}}&lt;br /&gt;
### {{level|Система непересекающихся множеств}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм DCSC поиска компонент сильной связности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна-Вишкина поиска компонент двусвязности}}&lt;br /&gt;
### {{level|Алгоритм Тарьяна поиска «мостов» в графе}}&lt;br /&gt;
### {{level|Определение вершинной связности графа}}&lt;br /&gt;
### {{level|Алгоритм Габова определения рёберной связности графа}}&lt;br /&gt;
## {{level|Поиск максимального потока в транспортной сети}}&lt;br /&gt;
### {{level|Алгоритм Форда-Фалкерсона}}&lt;br /&gt;
### {{level|Алгоритм проталкивания предпотока}}&lt;br /&gt;
## {{level|Поиск потока минимальной стоимости в транспортной сети}}&lt;br /&gt;
## {{level|Задача о назначениях}}&lt;br /&gt;
### {{level|Венгерский алгоритм}}&lt;br /&gt;
### {{level|Алгоритм аукциона}}&lt;br /&gt;
### {{level|Алгоритм Гопкрофта-Карпа}}&lt;br /&gt;
## {{level|Вычисление betweenness centrality|Вычисление центральности вершин}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы поиска&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы поиска&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Двоичный поиск - находит элемент в отсортированном списке}}, &amp;lt;math&amp;gt;O(log(n))&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы сортировки&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы сортировки&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Сортировка с помощью двоичного дерева}}&lt;br /&gt;
## {{level|Сортировка пузырьком}}&lt;br /&gt;
## {{level|Сортировка слиянием (последовательный и параллельный варианты)}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Вычислительная геометрия&amp;quot;&amp;gt;&#039;&#039;&#039;Вычислительная геометрия&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Поиск диаметра множества точек}}&lt;br /&gt;
## {{level|Построение выпуклой оболочки набора точек}}&lt;br /&gt;
## {{level|Триангуляция Делоне}}&lt;br /&gt;
## {{level|Диаграмма Вороного}}&lt;br /&gt;
## {{level|Принадлежность точки многоугольнику}}&lt;br /&gt;
## {{level|Пересечения выпуклых многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 + n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
## {{level|Пересечение звёздных многоугольников}} - трудоёмкость &amp;lt;math&amp;gt;O(n_1 * n_2)&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Компьютерная графика&amp;quot;&amp;gt;&#039;&#039;&#039;Компьютерная графика&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Алгоритмы построения отрезка - алгоритмы для аппроксимации отрезка на дискретной графической поверхности}}&lt;br /&gt;
## {{level|Алгоритм определения видимых частей трёхмерной сцены}}&lt;br /&gt;
## {{level|Трассировка лучей - рендеринг реалистичных изображений}}&lt;br /&gt;
## {{level|Глобальное освещение - рассматривает прямое освещение и отражение от других объектов}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Криптографические алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Криптографические алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Нейронные сети&amp;quot;&amp;gt;&#039;&#039;&#039;Нейронные сети&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы оптимизации&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы оптимизации&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Линейное программирование}}&lt;br /&gt;
## {{level|Симплекс-метод}}&lt;br /&gt;
## {{level|Метод ветвей и границ (последовательный и параллельный варианты)}}&lt;br /&gt;
## {{level|Генетические алгоритмы}}&lt;br /&gt;
## {{level|Муравьиные алгоритмы}}&lt;br /&gt;
## {{level|Комбинированные алгоритмы}}&lt;br /&gt;
## {{level|Нахождение экстремума функции}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы теории игр&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы теории игр&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы моделирования квантовых систем&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы моделирования квантовых систем&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## &#039;&#039;Алгоритмы моделирования квантовых вычислений&#039;&#039;&lt;br /&gt;
### {{level|Однокубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Двухкубитное преобразование вектора-состояния}}&lt;br /&gt;
### {{level|Моделирование квантового преобразования Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Алгоритмы решения уравнений математической физики&amp;quot;&amp;gt;&#039;&#039;&#039;Алгоритмы решения уравнений математической физики&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
## {{level|Уравнение Пуассона, решение дискретным преобразованием Фурье}}&lt;br /&gt;
# &amp;lt;div id=&amp;quot;Другие алгоритмы&amp;quot;&amp;gt;&#039;&#039;&#039;Другие алгоритмы&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3355</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=3355"/>
		<updated>2016-02-07T15:42:42Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласуется с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3345</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=3345"/>
		<updated>2016-02-06T17:44:23Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3344</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=3344"/>
		<updated>2016-02-06T17:30:51Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3343</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=3343"/>
		<updated>2016-02-06T10:11:07Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3331</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=3331"/>
		<updated>2016-02-04T16:45:46Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3324</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=3324"/>
		<updated>2016-02-04T13:02:26Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3323</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=3323"/>
		<updated>2016-02-04T13:01:34Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3321</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=3321"/>
		<updated>2016-02-04T12:39:20Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;0,...,N-1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1,...,N&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3320</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=3320"/>
		<updated>2016-02-04T12:34:42Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;0,...,N-1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1,...,N&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3319</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=3319"/>
		<updated>2016-02-04T12:31:00Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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; операций. Поскольку одномерное БПФ на каждом из 6 этапов алгоритма осуществляется &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;0,...,N-1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1,...,N&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3314</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=3314"/>
		<updated>2016-02-04T08:42:25Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
Рассмотрим случай куба, &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; операций. Поскольку одномерное БПФ на каждом из 6 этапов алгоритма осуществляется &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;0,...,N-1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1,...,N&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3313</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=3313"/>
		<updated>2016-02-04T07:52:42Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
Рассмотрим случай куба, &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; операций. Поскольку одномерное БПФ на каждом из 6 этапов алгоритма осуществляется &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;0,...,N-1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1,...,N&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with the DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</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=3312</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=3312"/>
		<updated>2016-02-03T20:00:53Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]], [[Участник:VadimVV|Вад.В.Воеводин]] ([[#Описание локальности данных и вычислений|раздел 2.2]])&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;
Рассмотрим случай куба, &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; операций. Поскольку одномерное БПФ на каждом из 6 этапов алгоритма осуществляется &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;0,...,N-1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;1,...,N&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;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_1.png|thumb|center|700px|Рисунок 3. Уравнение Пуассона, решение дискретным преобразованием Фурье. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации уравнения Пуассона, решение дискретным преобразованием Фурье. Данный профиль состоит из обращений к нескольким служебным массивам (фрагмент 1) и основному массиву (франмент 2). Видно, что профиль делится на два практически одинаковых этапа (вертикальная желтая линия). В целом можно отметить, что общее количество элементов невелико (чуть более 1000 элементов), при этом профиль составляет около 100 тысяч обращений. При этом видно, что в верхней части профиля плотность обращений выше, что говорит, вероятно, о высокой локальности вычислений; однако обращения к основному массиву достаточно разрознены. Перейдем к более детальному рассмотрению локальности.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен фрагмент 1, на котором расположены все обращения к служебным массивам. Исходя только из данного графика, нельзя сказать, какова структура обращения внутри блоков, однако в данном случае это и не требуется. Общее число задействованных адресов мало – всего порядка 100 элементов, при этом они используются в течение всей программы. Более того, они организованы в блочную структуру, что улучшает работу с памятью. Поэтому в данном случае можно с уверенностью сказать, что локальность (как пространственная, так и временная) в данном случае очень высока.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_2.png|thumb|center|700px|Рисунок 4. Профиль обращений, фрагмент 1]]&lt;br /&gt;
&lt;br /&gt;
Перейдем к рассмотрению основного массива. На рис. 5 представлен фрагмент 2 от общего профиля, показанного на рис. 3. Можно сразу же отметить следующий факт. На графике представлено максимум несколько сотен обращений, а по оси Х стоит отметка более 35000. Это значит, что значительно больше обращений происходит вне этого фрагмента, а именно в служебных массивах. То есть в целом обращения к основному массиву происходят не так часто. Это подтверждается при рассмотрении исходного кода программы: данные из основного массива на самом деле только копируются в служебные массивы, где над ними выполняются преобразование Фурье, после чего они копируются обратно.&lt;br /&gt;
&lt;br /&gt;
Согласно этому фрагменту, зачастую используемые подряд данные расположены достаточно близко, однако они редко используются повторно. То есть данный фрагмент обладает неплохой пространственной локальностью, но достаточно низкой временной.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_3.png|thumb|center|700px|Рисунок 5. Профиль обращений, фрагмент 2]]&lt;br /&gt;
&lt;br /&gt;
Поскольку основная масса обращений происходит к служебным массивам, а также вследствие достаточно высокой локальности обращений к основному массиву, в целом можно сказать, что общий профиль обладает как высокой пространственной, так и временной локальностью.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/poisson/poisson.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рис. 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Здесь мы можем наблюдать несколько неожиданный результат – производительность работы с памятью достаточно низкая, несмотря на предполагаемую высокую локальность. &lt;br /&gt;
&lt;br /&gt;
По всей видимости, причин несколько. Во-первых, постоянное копирование данных из и в служебные массивы портит как пространственную, так и временную локальность. Во-вторых, в служебных массивах над данными выполняется [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BB%D0%B8-%D0%A2%D1%8C%D1%8E%D0%BA%D0%B8_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%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%D1%8F_%D0%A4%D1%83%D1%80%D1%8C%D0%B5_%D0%B4%D0%BB%D1%8F_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B5%D0%B9_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BA%D0%B8 преобразование Фурье на основе алгоритма Кули-Тьюки], который, как видно по ссылке, показывает производительность работы с памятью, очень схожую с данной реализацией уравнения Пуассона. При этом выводы относительно локальности обращений к служебным массивам, над элементами которых выполняется преобразование Фурье, остаются верны - в случае алгоритма Кули-Тьюки локальность обращений в память также очень высока, несмотря на низкую производительность.&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подгружать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рис. 7 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем, в общем случае, выше локальность). Можно увидеть, что, как и в случае алгоритма Кули-Тьюки, локальность оценивается как очень высокая. Поскольку в данной программе реализации этого алгоритма посвящена большая часть общего профиля, то и причины такого расхождения между локальностью и производительностью в данных случаях одинаковы (см. подробное рассмотрение алгоритма Кули-Тьюки).&lt;br /&gt;
&lt;br /&gt;
[[file:poisson_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&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;
*	число процессоров [4 : 100] со значениями квадрата целого числа;&lt;br /&gt;
*	размер области [100x100x100 : 250x100x100] с шагом 50x100x100.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,132%;&lt;br /&gt;
*	максимальная эффективность реализации 1,34%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Poisson perf.png|thumb|center|700px|Рисунок 8. Параллельная реализация алгоритма. Изменение производительности в зависимости от числа процессоров и размера области.]]&lt;br /&gt;
[[file:Poisson eff.png|thumb|center|700px|Рисунок 9. Параллельная реализация алгоритма. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Приведенные результаты хорошо качественно согласуются с оценками, приведенными в предыдущем разделе. Так, на рис.8 видно, что с ростом &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; масштабируемость алгоритма повышается - производительность алгоритма быстрее растет с ростом числа ядер. Это согласутся с уменьшением &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; при увеличении &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, хотя выражение &amp;lt;math&amp;gt;\alpha=12/(6\log_2 N+1)&amp;lt;/math&amp;gt; дает значительно более слабую зависимость. В целом же, алгоритм масштабируется достаточно слабо: при максимальном из задаваемых размеров области 250х100х100 при росте числа ядер в 25 раз (от 4 до 100), производительность вычислений вырастает только в 6 раз.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&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.fftw.org/ FFTW]&lt;br /&gt;
| 1D&lt;br /&gt;
| MPI+OpenMP&lt;br /&gt;
| &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;
| [http://sdsc.github.io/p3dfft/ P3DFFT]&lt;br /&gt;
| 1D &amp;amp; 2D&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;
| [http://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;
| [https://software.intel.com/ru-ru/node/521992 MKL FFT]&lt;br /&gt;
| 1D&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;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;br /&gt;
Основные авторы описания: [[Участник:Виктор Степаненко|В.М.Степаненко]], [[Участник:Evgeny Mortikov|Е.В.Мортиков]]&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:Poisson equation, solving with DFT]]&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3286</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3286"/>
		<updated>2016-01-31T13:15:35Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки представлен на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - со степенью не более 2. При выполнении прямого хода не только сами ветви, но и две подветви каждой из них (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;. Вариант с заменой делений сводится к графу, изображённому на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода можно выполнять одновременно, если &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. В этом случае встречная прогонка требует последовательного выполнения следующих ярусов:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ встречная прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ сложность этого алгоритма равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно).&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;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней, если две основные ветви реализуются по отдельности на разных ядрах или же последовательно друг за другом &amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта встречной прогонки. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют два параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе профили для разных массивов отличаются, однако они также напоминают обычные последовательные переборы. Если это верно, то в целом данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо, задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу существенно последовательной природы алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]] или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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:Two-sided elimination method, pointwise version]]&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D0%BE%D0%B2%D1%82%D0%BE%D1%80%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3285</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%D0%B2%D1%82%D0%BE%D1%80%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3285"/>
		<updated>2016-01-31T12:57:03Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Повторная прогонка для нового СЛАУ с трёхдиагональной матрицей,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;5n-4&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;5n-4&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;4n-2&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;
[[file:ProgonkaRep.png|thumb|right|200px|Рисунок 1. Граф алгоритма повторной прогонки при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Повторная прогонка&#039;&#039;&#039; - часть метода [[Прогонка, точечный вариант|прогонки]] в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида&amp;lt;ref name=&amp;quot;SETKI&amp;quot;&amp;gt;Самарский А.А., Николаев Е.С. Методы решения сеточных уравнений. М.: Наука, 1978.&amp;lt;/ref&amp;gt; &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная_СЛАУ_в_сеточном_виде}}&lt;br /&gt;
&lt;br /&gt;
для того случая, когда ранее уже была выполнена прогонка для СЛАУ с той же матрицей, но с другой правой частью. В этом случае та часть формул прогонки, что связана только с матрицей, уже предвычислена, и повторять её не надо.  &lt;br /&gt;
[[file:ProgonkaRepMul.png|thumb|left|200px|Рисунок 2. Граф алгоритма повторной прогонки с предвычислением обратных чисел при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;m&#039;&#039;&#039; - умножение на предвычисленное обратное число, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#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;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = \beta_{N+1}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , 1, 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В литературе&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; указывается, что данные формулы эквивалентны вычислению решений двухдиагональных систем методом обратной подстановки в условиях предвычисленного &amp;lt;math&amp;gt;LU&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;
1. Инициализируется прямой ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
2. Последовательно для всех i от 1 до N-1 выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}).&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход прогонки:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
y_{N} = (f_{N}+a_{N}\beta_{N})/(c_{N}-a_{N}\alpha_{N})&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Последовательно для всех i с убыванием от N-1 до 0 выполняются формулы обратного хода:&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}.&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для быстрейшей работы повторной прогонки все деления в формулах заменяются умножением на предвычисленные обратные числа (&amp;lt;math&amp;gt;1/c_{0}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;1/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром, с предвычислением обратных чисел) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n-2&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, повторная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Информационный граф прогонки без предвычисления обратных чисел изображён на рис.1. Как видно, он последователен. Левая ветвь соответствует прямому, правая -  обратному ходу. По рисунку видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений на умножения даёт граф, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в параллельном варианте требуется последовательно выполнить следующие ярусы:&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;2n - 2&amp;lt;/math&amp;gt; ярусов умножений и сложений (все ярусы - по одной операции).&lt;br /&gt;
 &lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, повторная прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ его сложность будет &amp;lt;math&amp;gt;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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#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;
Вот пример подпрограммы, реализующей повторную прогонку, где предвычисленные коэффициенты хранятся на месте ненужных элементов матрицы. Предполагается, что уже однажды выполнена первая прогонка (см. [[Прогонка, точечный вариант#Особенности реализации последовательного алгоритма|пример из статьи о прогонке]]). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine prorep (a,x,N)&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      do 10 i=1,N-1&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
  10  continue&lt;br /&gt;
      x(N)=(x(N)-a(1,N)*x(N-1))*a(2,N) ! y N&lt;br /&gt;
      do 20 i=N-1,0,-1&lt;br /&gt;
        x(i)=a(3,i)*x(i+1)+x(i) ! y i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом углу&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций использующим прогонку - организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, его практически (без видоизменений) невозможно распараллелить. Поэтому есть два способа использования повторных прогонок для параллельных вычислительных систем: либо разбивать задачу, где используются прогонки, так, чтобы их было достаточно, чтобы на каждую из повторных прогонок приходился 1 процессор (1 ядро), либо использовать вместо прогонки её параллельные заменители (метод Стоуна, циклическую редукцию, последовательно-параллельные варианты и т.п.). Естественно, будет хорошо распараллеливаться вариант, когда все правые части СЛАУ известны сразу, и когда их много. Тогда каждая повторная прогонка будет вычисляться на отдельном узле вычислительной системы.&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой повторной прогонки, как непараллельного алгоритма, говорить нельзя в принципе. Однако необходимо указать на то, что сравнение параллельных заменителей прогонки при  изучении их масштабируемости должно идти не с однопроцессорными вариантами этих заменителей, а с выполнением на 1 процессоре самой повторной прогонки.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Повторная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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:Two-sided elimination method, pointwise version]] &lt;br /&gt;
[[Категория:Алгоритмы с низким уровнем параллелизма]]&lt;br /&gt;
[[Категория:Статьи в работе]]&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3284</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3284"/>
		<updated>2016-01-31T11:05:35Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки представлен на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - со степенью не более 2. При выполнении прямого хода не только сами ветви, но и две подветви каждой из них (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;. Вариант с заменой делений сводится к графу, изображённому на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода можно выполнять одновременно, если &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. В этом случае встречная прогонка требует последовательного выполнения следующих ярусов:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ встречная прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ сложность этого алгоритма равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно).&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;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней, если две основные ветви реализуются по отдельности на разных ядрах или же последовательно друг за другом &amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта встречной прогонки. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют два параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе профили для разных массивов отличаются, однако они также напоминают обычные последовательные переборы. Если это верно, то в целом данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо, задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу существенно последовательной природы алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]] или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3283</id>
		<title>Прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3283"/>
		<updated>2016-01-31T11:03:07Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-7&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;5n-4&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных, применяемого к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&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;. Суть метода состоит в исключении из уравнений неизвестных, сначала - сверху вниз - под диагональю, а затем - снизу вверх - над диагональю. Вариант, когда СЛАУ &amp;quot;проходится&amp;quot; наоборот, снизу вверх и обратно вниз - &#039;&#039;&#039;левая прогонка&#039;&#039;&#039; - принципиально ничем не отличается от рассматриваемого, поэтому нет смысла включать его отдельное описание.&lt;br /&gt;
&lt;br /&gt;
[[file:Progonka.png|thumb|right|200px|Рисунок 1. Граф алгоритма прогонки при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#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;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N-1&amp;lt;/math&amp;gt;,  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = \beta_{N+1}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , 1, 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В литературе&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; указывается, что данные формулы эквивалентны вычислению одного из вариантов &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложения матрицы системы с последующим решением двухдиагональных систем посредством прямой и обратной подстановок.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма можно считать состоящим из двух частей - прямого и обратного хода прогонки. В прямом ходе вычислительное ядро составляют последовательности операций деления, умножения и сложения/вычитания. В обратном ходе в вычислительном ядре остаются только последовательности умножения и сложения. &lt;br /&gt;
[[file:ProgonkaInv.png|thumb|left|420px|Рисунок 2. Детальный граф алгоритма прогонки с однократным вычислением обратных чисел при n=4 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым цветом выделены операции, повторяющиеся при замене правой части СЛАУ]]&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;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Последовательно для всех i от 1 до N-1 выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = (f_{N}+a_{N}\beta_{N})/(c_{N}-a_{N}\alpha_{N})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Последовательно для всех i с убыванием от N-1 до 0 выполняются формулы обратного хода:&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности, прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Информационный граф прогонки представлен на рис.1. Как следует из анализа графа, он является практически последовательным, при выполнении прямого хода две ветви (левая - разложение матрицы, центральная - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правая ветвь соответствует обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений сводится к графу, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2n - 2&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в n-1 ярусах - по 2 операции, в n-1 - по одной).&lt;br /&gt;
 &lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ её сложность будет равна &amp;lt;math&amp;gt;2&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;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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 2). &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;
В случае, когда требуется решение нескольких СЛАУ с одной и той же матрицей, левую ветвь вычислений (см. рисунки с графом алгоритма) можно не повторять. Это связано с тем, что &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложение матрицы системы не нужно перевычислять. Тогда будет более предпочтителен вариант с заменой делений.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В зависимости от способа хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов) и способа хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно) возможны различные реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
Приведем пример подпрограммы на языке Fortran, реализующей прогонку, где все элементы матрицы хранятся в одном массиве, причём соседние элементы матричной строки размещаются рядом, а вычисляемые коэффициенты --- на месте элементов исходной матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine progm (a,x,N)&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      do 10 i=1,N-1&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(3,i)=-a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
  10  continue&lt;br /&gt;
      a(2,N)=1./(a(2,N)+a(1,N)*a(2,N-1))&lt;br /&gt;
      x(N)=(x(N)-a(1,N)*x(N-1))*a(2,N) ! y N&lt;br /&gt;
      do 20 i=N-1,0,-1&lt;br /&gt;
        x(i)=a(3,i)*x(i+1)+x(i) ! y i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В Сети имеется много простых реализаций метода, например в [https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8 Викиучебник - Реализации алгоритмов - Метод прогонки]&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, которые необходимы для операций, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом углу&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, чтобы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;.&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность выполнения прогонки даже на современных однопроцессорных и одноядерных системах.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_1.png|thumb|center|700px|Рисунок 3. Прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта прогонки. Данный профиль состоит из обращений к 5 массивам – трем диагоналям матрицы, вектору правых частей и результирующему вектору. Исходя из общего профиля, можно увидеть, что программа состоит из двух этапов – на первом выполняется последовательный перебор элементов 4-х массивов, на втором – также последовательный перебор, только в обратном порядке.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
Однако при более детальном рассмотрении можно заметить, что профиль устроен несколько сложнее (рис. 4). Для некоторых массивов на каждом шаге выполняется по несколько очень близких обращений, что приводит к улучшению как пространственной, так и временной локальности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, общий профиль обладает высокой пространственной локальностью (поскольку здесь доминируют последовательные переборы элементов) и средней временной (поскольку некоторые элементы сразу используются повторно).&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal/tridiagonal.h здесь] (функция Kernel). Условия запуска описаны здесь [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 5 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Для данной программы значения daps является достаточно неожиданным. Согласно качественному анализу, локальность обращений в память в этом случае достаточно высока. Однако daps оценивает производительность работы с памятью ниже, чем для теста RandomAccess! Такое различие между локальностью и производительностью встречается нечасто.&lt;br /&gt;
&lt;br /&gt;
При детальном рассмотрении исходного кода выяснились две причины такого поведения. Во-первых, итерации основного цикла являются зависимыми по памяти, то есть на очередной итерации используются данные, посчитанные на предыдущей. Похоже, что в данном случае эта зависимость значительно снижает эффективность работы с памятью, в то время как с точки зрения локальности данный случай является достаточно неплохим.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что одна из операций деления неожиданно существенно замедляет выполнение программы. При замене этой операции на умножение время выполнения уменьшается в 2.5 раза, при этом ассемблерный код двух вариантов программы выглядел идентично (за исключением очевидной замены одной команды деления на команду умножения). &lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_daps.png|thumb|center|700px|Рисунок 5. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Такие особенности программы не отражаются в ее свойствах локальности, что и привело к такому существенному разрыву между оценкой локальности и производительностью работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, и тем лучше локальность алгоритма. &lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). В данном случае все предыдущие выводы подтверждаются – локальность оказывается достаточно высокой, что и было замечено согласно качественной оценке локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_cvg.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из анализа графа алгоритма, его (без существенных модификаций) практически невозможно распараллелить. Поэтому есть два способа использования прогонок для параллельных вычислительных систем: либо разбивать задачу, где используются прогонки, так, чтобы их было достаточно много, например, так, чтобы на каждую из прогонок приходился 1 процессор (1 ядро), либо использовать вместо прогонки её параллельные варианты (циклическую редукцию, последовательно-параллельные варианты и т.п.).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой прогонки, как полностью непараллельного алгоритма, говорить не имеет смысла. Однако необходимо отметить, что анализ масштабируемости параллельных вариантов прогонки должен проводиться относительно однопроцессорной реализации описанного классического варианта прогонки, а не относительно однопроцессорных расчетов для её параллельных вариантов.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.019%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0255%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Tridiag Perf.png|thumb|center|700px|Рисунок 7. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Tridiag eff.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Малая эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiag/tridiagonal.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу существенно последовательной природы алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Прогонка - метод для архитектуры классического, фон-неймановского типа, непригодный даже для эффективной загрузки одноядерных систем, поддерживающих суперскалярность. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует использовать какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]] или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный вариант]].&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм прогонки является настолько простым, что, несмотря на его &amp;quot;дежурное&amp;quot; присутствие в стандартных пакетах программ решения задач линейной алгебры, большинство использующих его исследователей-прикладников часто пишут соответствующий фрагмент программы самостоятельно. Однако надо отметить, что, как правило, метод прогонки в пакетах реализуют не в его &amp;quot;чистом виде&amp;quot;, а в виде пары &amp;quot;разложение на две двухдиагональные матрицы&amp;quot; и &amp;quot;решение СЛАУ с предварительно факторизованной трёхдиагональной матрицей&amp;quot;. Так обстоит дело, например, в пакете SCALAPACK и его предшественниках.&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:Elimination method, pointwise version]]&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3282</id>
		<title>Прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3282"/>
		<updated>2016-01-31T10:48:03Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-7&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;5n-4&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных, применяемого к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&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;. Суть метода состоит в исключении из уравнений неизвестных, сначала - сверху вниз - под диагональю, а затем - снизу вверх - над диагональю. Вариант, когда СЛАУ &amp;quot;проходится&amp;quot; наоборот, снизу вверх и обратно вниз - &#039;&#039;&#039;левая прогонка&#039;&#039;&#039; - принципиально ничем не отличается от рассматриваемого, поэтому нет смысла включать его отдельное описание.&lt;br /&gt;
&lt;br /&gt;
[[file:Progonka.png|thumb|right|200px|Рисунок 1. Граф алгоритма прогонки при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#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;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N-1&amp;lt;/math&amp;gt;,  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = \beta_{N+1}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , 1, 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В литературе&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; указывается, что данные формулы эквивалентны вычислению одного из вариантов &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложения матрицы системы с последующим решением двухдиагональных систем посредством прямой и обратной подстановок.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма можно считать состоящим из двух частей - прямого и обратного хода прогонки. В прямом ходе вычислительное ядро составляют последовательности операций деления, умножения и сложения/вычитания. В обратном ходе в вычислительном ядре остаются только последовательности умножения и сложения. &lt;br /&gt;
[[file:ProgonkaInv.png|thumb|left|420px|Рисунок 2. Детальный граф алгоритма прогонки с однократным вычислением обратных чисел при n=4 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым цветом выделены операции, повторяющиеся при замене правой части СЛАУ]]&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;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Последовательно для всех i от 1 до N-1 выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = (f_{N}+a_{N}\beta_{N})/(c_{N}-a_{N}\alpha_{N})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Последовательно для всех i с убыванием от N-1 до 0 выполняются формулы обратного хода:&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности, прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Информационный граф прогонки представлен на рис.1. Как следует из анализа графа, он является практически последовательным, при выполнении прямого хода две ветви (левая - разложение матрицы, центральная - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правая ветвь соответствует обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений сводится к графу, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2n - 2&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в n-1 ярусах - по 2 операции, в n-1 - по одной).&lt;br /&gt;
 &lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ её сложность будет равна &amp;lt;math&amp;gt;2&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;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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 2). &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;
В случае, когда требуется решение нескольких СЛАУ с одной и той же матрицей, левую ветвь вычислений (см. рисунки с графом алгоритма) можно не повторять. Это связано с тем, что &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложение матрицы системы не нужно перевычислять. Тогда будет более предпочтителен вариант с заменой делений.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В зависимости от способа хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов) и способа хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно) возможны различные реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
Приведем пример подпрограммы на языке Fortran, реализующей прогонку, где все элементы матрицы хранятся в одном массиве, причём соседние элементы матричной строки размещаются рядом, а вычисляемые коэффициенты --- на месте элементов исходной матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine progm (a,x,N)&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      do 10 i=1,N-1&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(3,i)=-a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
  10  continue&lt;br /&gt;
      a(2,N)=1./(a(2,N)+a(1,N)*a(2,N-1))&lt;br /&gt;
      x(N)=(x(N)-a(1,N)*x(N-1))*a(2,N) ! y N&lt;br /&gt;
      do 20 i=N-1,0,-1&lt;br /&gt;
        x(i)=a(3,i)*x(i+1)+x(i) ! y i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В Сети имеется много простых реализаций метода, например в [https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8 Викиучебник - Реализации алгоритмов - Метод прогонки]&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, которые необходимы для операций, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом углу&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, чтобы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;.&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность выполнения прогонки даже на современных однопроцессорных и одноядерных системах.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_1.png|thumb|center|700px|Рисунок 3. Прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта прогонки. Данный профиль состоит из обращений к 5 массивам – трем диагоналям матрицы, вектору правых частей и результирующему вектору. Исходя из общего профиля, можно увидеть, что программа состоит из двух этапов – на первом выполняется последовательный перебор элементов 4-х массивов, на втором – также последовательный перебор, только в обратном порядке.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
Однако при более детальном рассмотрении можно заметить, что профиль устроен несколько сложнее (рис. 4). Для некоторых массивов на каждом шаге выполняется по несколько очень близких обращений, что приводит к улучшению как пространственной, так и временной локальности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, общий профиль обладает высокой пространственной локальностью (поскольку здесь доминируют последовательные переборы элементов) и средней временной (поскольку некоторые элементы сразу используются повторно).&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal/tridiagonal.h здесь] (функция Kernel). Условия запуска описаны здесь [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 5 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Для данной программы значения daps является достаточно неожиданным. Согласно качественному анализу, локальность обращений в память в этом случае достаточно высока. Однако daps оценивает производительность работы с памятью ниже, чем для теста RandomAccess! Такое различие между локальностью и производительностью встречается нечасто.&lt;br /&gt;
&lt;br /&gt;
При детальном рассмотрении исходного кода выяснились две причины такого поведения. Во-первых, итерации основного цикла являются зависимыми по памяти, то есть на очередной итерации используются данные, посчитанные на предыдущей. Похоже, что в данном случае эта зависимость значительно снижает эффективность работы с памятью, в то время как с точки зрения локальности данный случай является достаточно неплохим.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что одна из операций деления неожиданно существенно замедляет выполнение программы. При замене этой операции на умножение время выполнения уменьшается в 2.5 раза, при этом ассемблерный код двух вариантов программы выглядел идентично (за исключением очевидной замены одной команды деления на команду умножения). &lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_daps.png|thumb|center|700px|Рисунок 5. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Такие особенности программы не отражаются в ее свойствах локальности, что и привело к такому существенному разрыву между оценкой локальности и производительностью работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, и тем лучше локальность алгоритма. &lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). В данном случае все предыдущие выводы подтверждаются – локальность оказывается достаточно высокой, что и было замечено согласно качественной оценке локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_cvg.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из анализа графа алгоритма, его (без существенных модификаций) практически невозможно распараллелить. Поэтому есть два способа использования прогонок для параллельных вычислительных систем: либо разбивать задачу, где используются прогонки, так, чтобы их было достаточно много, например, так, чтобы на каждую из прогонок приходился 1 процессор (1 ядро), либо использовать вместо прогонки её параллельные варианты (циклическую редукцию, последовательно-параллельные варианты и т.п.).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой прогонки, как полностью непараллельного алгоритма, говорить не имеет смысла. Однако необходимо отметить, что анализ масштабируемости параллельных вариантов прогонки должен проводиться относительно однопроцессорной реализации описанного классического варианта прогонки, а не относительно однопроцессорных расчетов для её параллельных вариантов.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.019%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0255%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Tridiag Perf.png|thumb|center|700px|Рисунок 7. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Tridiag eff.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Малая эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiag/tridiagonal.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу существенно последовательной природы алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Прогонка - метод для архитектуры классического, фон-неймановского типа, непригодный даже для эффективной загрузки одноядерных систем, поддерживающих суперскалярность. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует использовать какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный вариант]].&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм прогонки является настолько простым, что, несмотря на его &amp;quot;дежурное&amp;quot; присутствие в стандартных пакетах программ решения задач линейной алгебры, большинство использующих его исследователей-прикладников часто пишут соответствующий фрагмент программы самостоятельно. Однако надо отметить, что, как правило, метод прогонки в пакетах реализуют не в его &amp;quot;чистом виде&amp;quot;, а в виде пары &amp;quot;разложение на две двухдиагональные матрицы&amp;quot; и &amp;quot;решение СЛАУ с предварительно факторизованной трёхдиагональной матрицей&amp;quot;. Так обстоит дело, например, в пакете SCALAPACK и его предшественниках.&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:Elimination method, pointwise version]]&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3281</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3281"/>
		<updated>2016-01-31T10:45:25Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки представлен на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - со степенью не более 2. При выполнении прямого хода не только сами ветви, но и две подветви каждой из них (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;. Вариант с заменой делений сводится к графу, изображённому на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода можно выполнять одновременно, если &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. В этом случае встречная прогонка требует последовательного выполнения следующих ярусов:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ встречная прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ сложность этого алгоритма равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно).&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;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней, если две основные ветви реализуются по отдельности на разных ядрах или же последовательно друг за другом &amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта встречной прогонки. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют два параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе профили для разных массивов отличаются, однако они также напоминают обычные последовательные переборы. Если это верно, то в целом данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо, задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные были не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма, и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3280</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3280"/>
		<updated>2016-01-31T10:29:32Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки представлен на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - со степенью не более 2. При выполнении прямого хода не только сами ветви, но и две подветви каждой из них (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;. Вариант с заменой делений сводится к графу, изображённому на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода можно выполнять одновременно, если &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. В этом случае встречная прогонка требует последовательного выполнения следующих ярусов:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ встречная прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ сложность этого алгоритма равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно).&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;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней, если две основные ветви реализуются по отдельности на разных ядрах или же последовательно друг за другом &amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации встречной прогонки, точечный вариант. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют две параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе для разных массивов профили отличаются, однако также напоминают обычные последовательные переборы. Если это верно, в общем данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо также задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные были не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма, и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3279</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3279"/>
		<updated>2016-01-31T09:59:48Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки представлен на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - со степенью не более 2. При выполнении прямого хода не только сами ветви, но и две подветви каждой из них (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;. Вариант с заменой делений сводится к графу, изображённому на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода можно выполнять одновременно, если &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. В этом случае встречная прогонка требует последовательного выполнения следующих ярусов:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ встречная прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ сложность этого алгоритма равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте использованных уже элементов матрицы либо отдельно).&lt;br /&gt;
&lt;br /&gt;
Вот пример подпрограммы, реализующей встречную прогонку, где все элементы матрицы размещены в 1 массиве, причём соседние по строке - рядом, а вычисляемые коэффициенты хранятся на месте ненужных элементов матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что, если две основные ветви реализовать по отдельности на разных ядрах, или же последовательно друг за другом, то будет излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, нужные для вычислений основных операций алгоритма прогонки, вычисляются в её процессе операциями, непосредственно предшествующими им, возможности вычислительных ядер процессоров по использованию своей суперскалярности практически сводятся на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации встречной прогонки, точечный вариант. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют две параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе для разных массивов профили отличаются, однако также напоминают обычные последовательные переборы. Если это верно, в общем данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо также задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные были не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма, и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3278</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3278"/>
		<updated>2016-01-30T18:09:16Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки представлен на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - со степенью не более 2. При выполнении прямого хода не только сами ветви, но и две подветви каждой из них (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;. Вариант с заменой делений сводится к графу, изображённому на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода выполняются одновременно для &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. для &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. Тогда для выполнения встречной прогонки требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ его сложность будет равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте использованных уже элементов матрицы либо отдельно).&lt;br /&gt;
&lt;br /&gt;
Вот пример подпрограммы, реализующей встречную прогонку, где все элементы матрицы размещены в 1 массиве, причём соседние по строке - рядом, а вычисляемые коэффициенты хранятся на месте ненужных элементов матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что, если две основные ветви реализовать по отдельности на разных ядрах, или же последовательно друг за другом, то будет излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, нужные для вычислений основных операций алгоритма прогонки, вычисляются в её процессе операциями, непосредственно предшествующими им, возможности вычислительных ядер процессоров по использованию своей суперскалярности практически сводятся на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации встречной прогонки, точечный вариант. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют две параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе для разных массивов профили отличаются, однако также напоминают обычные последовательные переборы. Если это верно, в общем данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо также задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные были не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма, и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3277</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3277"/>
		<updated>2016-01-30T18:00:20Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для компоненты &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, которая вычисляется позже в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислена &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу, для разных половин СЛАУ.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа (см. Рисунок 2). &lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности встречная прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки изображён на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - не более 2. При выполнении прямого хода не только ветви, но и две подветви каждой из ветвей (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. По рисунку видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений даёт граф, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода выполняются одновременно для &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. для &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. Тогда для выполнения встречной прогонки требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ его сложность будет равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте использованных уже элементов матрицы либо отдельно).&lt;br /&gt;
&lt;br /&gt;
Вот пример подпрограммы, реализующей встречную прогонку, где все элементы матрицы размещены в 1 массиве, причём соседние по строке - рядом, а вычисляемые коэффициенты хранятся на месте ненужных элементов матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что, если две основные ветви реализовать по отдельности на разных ядрах, или же последовательно друг за другом, то будет излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, нужные для вычислений основных операций алгоритма прогонки, вычисляются в её процессе операциями, непосредственно предшествующими им, возможности вычислительных ядер процессоров по использованию своей суперскалярности практически сводятся на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации встречной прогонки, точечный вариант. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют две параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе для разных массивов профили отличаются, однако также напоминают обычные последовательные переборы. Если это верно, в общем данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо также задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные были не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма, и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3276</id>
		<title>Встречная прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%92%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3276"/>
		<updated>2016-01-30T17:14:21Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Встречная прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-2&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;2.5n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;4&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных в приложении к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &lt;br /&gt;
&lt;br /&gt;
{{Шаблон:Трёхдиагональная СЛАУ}}&lt;br /&gt;
&#039;&#039;&#039;Встречная прогонка&#039;&#039;&#039;, как и [[Прогонка, точечный вариант|классическая монотонная]], заключается в исключении из уравнений неизвестных, однако, в отличие от монотонной, в ней исключение ведут одновременно с обоих &amp;quot;краёв&amp;quot; СЛАУ (верхнего и нижнего). В принципе, её можно считать простейшим вариантом [[Метод редукции|метода редукции]] (при m=1 и встречных направлениях монотонных прогонок).&lt;br /&gt;
&lt;br /&gt;
[[file:VstrProgonka.png|thumb|right|600px|Рисунок 1. Граф алгоритма встречной прогонки при n=14 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#039;&#039;&#039;&#039;&#039;.]]&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; здесь - номер уравнения, на котором &amp;quot;встречаются&amp;quot; две ветви прямого хода - &amp;quot;сверху&amp;quot; и &amp;quot;снизу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
В приведенных обозначениях во встречной прогонке сначала выполняют её прямой ход - вычисляют коэффициенты&lt;br /&gt;
&lt;br /&gt;
&amp;quot;сверху&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}, &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i}), \quad i = 1, 2, \cdots , m-1.&lt;br /&gt;
&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;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{N} = f_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}, \quad i = m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}, \quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В обычно приводимых&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; формулах встречной прогонки нет формулы для &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt;, который вычисляется затем в обратном ходе. Однако это удлиняет критический путь графа, откладывая вычисление &amp;lt;math&amp;gt;y_{m-1}&amp;lt;/math&amp;gt; на момент, когда уже будет вычислен &amp;lt;math&amp;gt;y_{m}&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;quot;одновременно&amp;quot;, т.е., параллельно друг другу. Обратный ход также может быть разложен на две макроединицы - обратный ход правой и левой прогонок, выполняемых для разных половин СЛАУ, которые выполняются &amp;quot;одновременно&amp;quot;, т.е., параллельно друг другу.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
[[file:VstrProgonkaInv.png|thumb|left|600px|Рисунок 2. Детальный граф алгоритма встречной прогонки с однократным вычислением обратных чисел при n=6 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым выделены операции, повторяющиеся при замене правой части СЛАУ]]&lt;br /&gt;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{N} = a_{N}/c_{N}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{1} = f_{N}/c_{N}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Последовательно выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , m-1&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\xi_{i} = a_{i}/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\eta_{i} = (f_{i}+b_{i}\eta_{i+1})/(c_{i}-b_{i}\xi_{i+1})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m-1} = (\beta_{m}+\alpha_{m}\eta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{m} = (\eta_{m}+\xi_{m}\beta_{m})/(1-\xi_{m}\alpha_{m})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
4. Последовательно выполняются формулы обратного хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m-1, m-2, \cdots , 1, 0&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i+1} = \xi_{i+1} y_{i} + \eta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = m, m+1, \cdots , N-1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В связи с тем, что почти во всех формулах есть пары делений на одно и то же выражение, можно поменять их на последовательности вычисления обратных чисел с последующими умножениями на ниx (см. Рисунок 2)&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения встречной прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n+2&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-2&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Информационный граф встречной прогонки изображён на рис.1. Как видно, он параллелен на прямом ходе со степенью не более 4, на обратном - не более 2. При выполнении прямого хода не только ветви, но и две подветви каждой из ветвей (левая - разложение матрицы, правая - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правые подветви соответствуют обратному ходу. По рисунку видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений даёт граф, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Обе ветви прямого хода выполняются одновременно для &amp;lt;math&amp;gt;N=2m-1&amp;lt;/math&amp;gt;, т.е. для &amp;lt;math&amp;gt;n=2m&amp;lt;/math&amp;gt;. Тогда для выполнения встречной прогонки требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m+1&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 4 деления, в одном - 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2m-1&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; ярусах - по 4 операции, в &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; - по две, в одном - три операции).&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ его сложность будет равна &amp;lt;math&amp;gt;4&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;
&#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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 4). &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;
&lt;br /&gt;
В зависимости от нужд вычислений, возможны как разные способы хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов), так и разные способы хранения вычисляемых коэффициентов (на месте использованных уже элементов матрицы либо отдельно).&lt;br /&gt;
&lt;br /&gt;
Вот пример подпрограммы, реализующей встречную прогонку, где все элементы матрицы размещены в 1 массиве, причём соседние по строке - рядом, а вычисляемые коэффициенты хранятся на месте ненужных элементов матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine vprogm (a,x,N) ! N=2m-1&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
&lt;br /&gt;
      m=(N+1)/2&lt;br /&gt;
&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(2,N)=1./a(2,N)&lt;br /&gt;
&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      a(1,N)=-a(1,N)*a(2,N) ! xi N&lt;br /&gt;
&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      x(N)=x(N)*a(2,N) ! eta N&lt;br /&gt;
&lt;br /&gt;
      do 10 i=1,m-1&lt;br /&gt;
&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(2,N-i)=1./(a(2,N-i)+a(3,N-i)*a(2,N-i+1))&lt;br /&gt;
&lt;br /&gt;
        a(3,i) = -a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        a(1,N-i) = -a(1,N-i)*a(2,N-i) ! xi N-i&lt;br /&gt;
&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
        x(N-i)=(x(N-i)-a(3,N-i)*x(N-i+1))* a(2,N-i) ! eta N-i&lt;br /&gt;
&lt;br /&gt;
  10  continue&lt;br /&gt;
&lt;br /&gt;
      a(1,0)=1./(1.-a(1,m)*a(3,m-1))&lt;br /&gt;
      bb=x(m-1)&lt;br /&gt;
      ee=x(m)&lt;br /&gt;
      x(m-1)=(bb+a(3,m-1)*ee))*a(1,0) ! y m-1&lt;br /&gt;
      x(m) = (ee+a(1,m)*bb)*a(1,0) ! y m&lt;br /&gt;
&lt;br /&gt;
      do 20 i=m+1,N&lt;br /&gt;
        x(i)=a(1,i)*x(i-1)+x(i) ! y i&lt;br /&gt;
        x(N-i)=a(3,N-i)*x(N-i+1)+x(i) ! y N-i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, что нужны операциям, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом&amp;quot; и &amp;quot;нижнем правом&amp;quot; &amp;quot;углах&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, что бы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что, если две основные ветви реализовать по отдельности на разных ядрах, или же последовательно друг за другом, то будет излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;&amp;lt;/ref&amp;gt;. Из-за того, что данные, нужные для вычислений основных операций алгоритма прогонки, вычисляются в её процессе операциями, непосредственно предшествующими им, возможности вычислительных ядер процессоров по использованию своей суперскалярности практически сводятся на нет, что резко ухудшает эффективность исполнения прогонки даже на современных однопроцессорных и одноядерных системах. Именно поэтому в примере п.2.1 обе ветви (как прямого, так и обратного хода) сведены в общий цикл. Это, однако, даёт выигрыш только по сравнению с чересчур локальной монотонной прогонкой, ибо эффективность остаётся малой.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_1.png|thumb|center|700px|Рисунок 3. Встречная прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации встречной прогонки, точечный вариант. Данный профиль состоит из двух этапов (разделены желтой линией), на каждом из которых выполняются обращения к 4-м массивам. Обращения к разным массивам разделены зелеными горизонтальными линиями. Исходя из общего профиля, можно предположить, что на первом этапе ко всем массивам выполняются примерно одни и те же обращения, которые в каждом случае формируют две параллельно выполняемых последовательных перебора, один по возрастанию элементов массива, другой – по убыванию. &lt;br /&gt;
&lt;br /&gt;
На втором этапе для разных массивов профили отличаются, однако также напоминают обычные последовательные переборы. Если это верно, в общем данный профиль обладает высокой пространственной локальностью (обращения к соседним элементам следуют близко друг от друга) и достаточно низкой временной (повторное использование данных практически отсутствует). Рассмотрим профиль более детально и проверим, так ли это.&lt;br /&gt;
&lt;br /&gt;
На рис. 4 представлен выделенный зеленым фрагмент общего профиля. Здесь видно, что обращения к 4-м массивам обладают регулярной структурой, при этом действительно соседние элементы задействованы рядом. Однако сложно определить с точностью до отдельных обращений, как они устроены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
На рис. 5 отдельно рассмотрены профили из рис. 4. При таком рассмотрении видно, что в целом все профили действительно состоят из последовательных переборов, только на каждом шаге перебора выполняется разное число обращений. В профиле на рис. 5а на каждом шаге задействован текущий и предыдущий элементы; в профиле на рис. 5б, видимо также задействован еще и следующий элемент. Профили 5в и 5г устроены чуть проще – только в одном переборе на каждом шаге выполняются два обращения.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_3.png|thumb|center|700px|Рисунок 5. Отдельные профили для разных массивов]]&lt;br /&gt;
&lt;br /&gt;
Исходя из полученной информации, можно сделать вывод, что локальность обращений даже лучше, чем мы предположили при рассмотрении общего профиля. Это связано с тем, что во многих случаях одни и те же данные используются подряд несколько раз, что повышает как пространственную, так и временную локальность.&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal_other/tridiagonal_other.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). В целом значение daps для данной программы показывает достаточно высокую производительность работы с памятью, что соответствует нашим ожиданиям согласно приведенному выше описанию локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_daps.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, тем лучше локальность. &lt;br /&gt;
&lt;br /&gt;
На рисунке 7 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). Для этой программы оценка cvg очень высока, даже лучше, чем в случае теста Linpack. Здесь можно отметить довольно заметную разницу между двумя оценками, daps и cvg. Возможные причины такой разницы здесь могут быть те же, что и в случае обычной прогонки, которые описаны [http://algowiki-project.org/ru/%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82#.D0.9B.D0.BE.D0.BA.D0.B0.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D1.8C_.D0.B4.D0.B0.D0.BD.D0.BD.D1.8B.D1.85_.D0.B8_.D0.B2.D1.8B.D1.87.D0.B8.D1.81.D0.BB.D0.B5.D0.BD.D0.B8.D0.B9 здесь].&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal2_cvg.png|thumb|center|700px|Рисунок 7. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка задумана изначально для случая, когда нужно найти только какую-то близкую к &amp;quot;середине&amp;quot; компоненту вектора решения, а остальные были не нужны (решение т.н. &amp;quot;частичной задачи&amp;quot;). При появлении параллельных компьютерных устройств оказалось, что у встречной прогонки есть небольшой ресурс параллелизма, и она убыстряет счёт, если её верхнюю и нижнюю ветви раскидать на 2 процессора. Однако для получения массового параллелизма встречная прогонка непригодна из-за низкой ширины своей [[Глоссарий#Ярусно-параллельная форма графа алгоритма|ЯПФ]] (равной 4 на прямом и 2 - на обратном ходе).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой встречной прогонки, как почти непараллельного алгоритма, говорить нельзя в принципе, за исключением разве что двухпроцессорных систем. Понятие масштабируемости неприменимо, поскольку описываемый алгоритм не предполагает параллельной реализации.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.0634%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0651%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Vstr perf.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Vstr eff.png|thumb|center|700px|Рисунок 9. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Мизерная эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiagonal_other/tridiagonal_other.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Встречная прогонка - метод для архитектуры классического, фон-неймановского типа. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует взять какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный метод]].&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3268</id>
		<title>Прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3268"/>
		<updated>2016-01-28T07:08:53Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-7&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;5n-4&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных, применяемого к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&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;. Суть метода состоит в исключении из уравнений неизвестных, сначала - сверху вниз - под диагональю, а затем - снизу вверх - над диагональю. Вариант, когда СЛАУ &amp;quot;проходится&amp;quot; наоборот, снизу вверх и обратно вниз - &#039;&#039;&#039;левая прогонка&#039;&#039;&#039; - принципиально ничем не отличается от рассматриваемого, поэтому нет смысла включать его отдельное описание.&lt;br /&gt;
&lt;br /&gt;
[[file:Progonka.png|thumb|right|200px|Рисунок 1. Граф алгоритма прогонки при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#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;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N-1&amp;lt;/math&amp;gt;,  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = \beta_{N+1}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , 1, 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В литературе&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; указывается, что данные формулы эквивалентны вычислению одного из вариантов &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложения матрицы системы с последующим решением двухдиагональных систем посредством прямой и обратной подстановок.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма можно считать состоящим из двух частей - прямого и обратного хода прогонки. В прямом ходе вычислительное ядро составляют последовательности операций деления, умножения и сложения/вычитания. В обратном ходе в вычислительном ядре остаются только последовательности умножения и сложения. &lt;br /&gt;
[[file:ProgonkaInv.png|thumb|left|420px|Рисунок 2. Детальный граф алгоритма прогонки с однократным вычислением обратных чисел при n=4 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым цветом выделены операции, повторяющиеся при замене правой части СЛАУ]]&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;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Последовательно для всех i от 1 до N-1 выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = (f_{N}+a_{N}\beta_{N})/(c_{N}-a_{N}\alpha_{N})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Последовательно для всех i с убыванием от N-1 до 0 выполняются формулы обратного хода:&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности, прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Информационный граф прогонки представлен на рис.1. Как следует из анализа графа, он является практически последовательным, при выполнении прямого хода две ветви (левая - разложение матрицы, центральная - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правая ветвь соответствует обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений сводится к графу, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2n - 2&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в n-1 ярусах - по 2 операции, в n-1 - по одной).&lt;br /&gt;
 &lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ её сложность будет равна &amp;lt;math&amp;gt;2&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;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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 2). &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;
В случае, когда требуется решение нескольких СЛАУ с одной и той же матрицей, левую ветвь вычислений (см. рисунки с графом алгоритма) можно не повторять. Это связано с тем, что &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложение матрицы системы не нужно перевычислять. Тогда будет более предпочтителен вариант с заменой делений.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В зависимости от способа хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов) и способа хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно) возможны различные реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
Приведем пример подпрограммы на языке Fortran, реализующей прогонку, где все элементы матрицы хранятся в одном массиве, причём соседние элементы матричной строки размещаются рядом, а вычисляемые коэффициенты --- на месте элементов исходной матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine progm (a,x,N)&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      do 10 i=1,N-1&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(3,i)=-a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
  10  continue&lt;br /&gt;
      a(2,N)=1./(a(2,N)+a(1,N)*a(2,N-1))&lt;br /&gt;
      x(N)=(x(N)-a(1,N)*x(N-1))*a(2,N) ! y N&lt;br /&gt;
      do 20 i=N-1,0,-1&lt;br /&gt;
        x(i)=a(3,i)*x(i+1)+x(i) ! y i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В Сети имеется много простых реализаций метода, например в [https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8 Викиучебник - Реализации алгоритмов - Метод прогонки]&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, которые необходимы для операций, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом углу&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, чтобы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;.&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность выполнения прогонки даже на современных однопроцессорных и одноядерных системах.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_1.png|thumb|center|700px|Рисунок 3. Прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта прогонки. Данный профиль состоит из обращений к 5 массивам – трем диагоналям матрицы, вектору правых частей и результирующему вектору. Исходя из общего профиля, можно увидеть, что программа состоит из двух этапов – на первом выполняется последовательный перебор элементов 4-х массивов, на втором – также последовательный перебор, только в обратном порядке.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
Однако при более детальном рассмотрении можно заметить, что профиль устроен несколько сложнее (рис. 4). Для некоторых массивов на каждом шаге выполняется по несколько очень близких обращений, что приводит к улучшению как пространственной, так и временной локальности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, общий профиль обладает высокой пространственной локальностью (поскольку здесь доминируют последовательные переборы элементов) и средней временной (поскольку некоторые элементы сразу используются повторно).&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal/tridiagonal.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 5 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Для данной программы значения daps является достаточно неожиданным. Согласно качественному анализу, локальность обращений в память в этом случае достаточно высока. Однако daps оценивает производительность работы с памятью ниже, чем для теста RandomAccess! Такое различие между локальностью и производительностью встречается нечасто.&lt;br /&gt;
&lt;br /&gt;
При детальном рассмотрении исходного кода выяснились две причины такого поведения. Во-первых, итерации основного цикла являются зависимыми по памяти, то есть на очередной итерации используются данные, посчитанные на предыдущей. Похоже, что в данном случае эта зависимость значительно снижает эффективность работы с памятью, в то время как с точки зрения локальности данный случай является достаточно неплохим.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что одна из операций деления неожиданно существенно замедляет выполнение программы. При замене этой операции на умножение время выполнения уменьшается в 2.5 раза, при этом ассемблерный код двух вариантов программы выглядел идентично (за исключением очевидной замены одной команды деления на команду умножения). &lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_daps.png|thumb|center|700px|Рисунок 5. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Такие особенности программы не отражаются в ее свойствах локальности, что и привело к такому существенному разрыву между оценкой локальности и производительностью работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, и тем лучше локальность алгоритма. &lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). В данном случае все предыдущие выводы подтверждаются – локальность оказывается достаточно высокой, что и было замечено согласно качественной оценке локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_cvg.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из анализа графа алгоритма, его (без существенных модификаций) практически невозможно распараллелить. Поэтому есть два способа использования прогонок для параллельных вычислительных систем: либо разбивать задачу, где используются прогонки, так, чтобы их было достаточно много, например, так, чтобы на каждую из прогонок приходился 1 процессор (1 ядро), либо использовать вместо прогонки её параллельные варианты (циклическую редукцию, последовательно-параллельные варианты и т.п.).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой прогонки, как полностью непараллельного алгоритма, говорить не имеет смысла. Однако необходимо отметить, что анализ масштабируемости параллельных вариантов прогонки должен проводиться относительно однопроцессорной реализации описанного классического варианта прогонки, а не относительно однопроцессорных расчетов для её параллельных вариантов.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.019%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0255%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Tridiag Perf.png|thumb|center|700px|Рисунок 7. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Tridiag eff.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Малая эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiag/tridiagonal.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу существенно последовательной природы алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Прогонка - метод для архитектуры классического, фон-неймановского типа, непригодный даже для эффективной загрузки одноядерных систем, поддерживающих суперскалярность. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует использовать какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный вариант]].&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм прогонки является настолько простым, что, несмотря на его &amp;quot;дежурное&amp;quot; присутствие в стандартных пакетах программ решения задач линейной алгебры, большинство использующих его исследователей-прикладников часто пишут соответствующий фрагмент программы самостоятельно. Однако надо отметить, что, как правило, метод прогонки в пакетах реализуют не в его &amp;quot;чистом виде&amp;quot;, а в виде пары &amp;quot;разложение на две двухдиагональные матрицы&amp;quot; и &amp;quot;решение СЛАУ с предварительно факторизованной трёхдиагональной матрицей&amp;quot;. Так обстоит дело, например, в пакете SCALAPACK и его предшественниках.&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:Elimination method, pointwise version]]&lt;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3267</id>
		<title>Прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3267"/>
		<updated>2016-01-27T17:08:41Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-7&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;5n-4&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных, применяемого к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&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;. Суть метода состоит в исключении из уравнений неизвестных, сначала - сверху вниз - под диагональю, а затем - снизу вверх - над диагональю. Вариант, когда СЛАУ &amp;quot;проходится&amp;quot; наоборот, снизу вверх и обратно вниз - &#039;&#039;&#039;левая прогонка&#039;&#039;&#039; - принципиально ничем не отличается от рассматриваемого, поэтому нет смысла включать его отдельное описание.&lt;br /&gt;
&lt;br /&gt;
[[file:Progonka.png|thumb|right|200px|Рисунок 1. Граф алгоритма прогонки при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#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;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N-1&amp;lt;/math&amp;gt;,  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = \beta_{N+1}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , 1, 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В литературе&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; указывается, что данные формулы эквивалентны вычислению одного из вариантов &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложения матрицы системы с последующим решением двухдиагональных систем посредством прямой и обратной подстановок.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма можно считать состоящим из двух частей - прямого и обратного хода прогонки. В прямом ходе вычислительное ядро составляют последовательности операций деления, умножения и сложения/вычитания. В обратном ходе в вычислительном ядре остаются только последовательности умножения и сложения. &lt;br /&gt;
[[file:ProgonkaInv.png|thumb|left|420px|Рисунок 2. Детальный граф алгоритма прогонки с однократным вычислением обратных чисел при n=4 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым цветом выделены операции, повторяющиеся при замене правой части СЛАУ]]&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;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Последовательно для всех i от 1 до N-1 выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = (f_{N}+a_{N}\beta_{N})/(c_{N}-a_{N}\alpha_{N})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Последовательно для всех i с убыванием от N-1 до 0 выполняются формулы обратного хода:&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности, прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Информационный граф прогонки представлен на рис.1. Как следует из анализа графа, он является практически последовательным, при выполнении прямого хода две ветви (левая - разложение матрицы, центральная - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правая ветвь соответствует обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений сводится к графу, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2n - 2&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в n-1 ярусах - по 2 операции, в n-1 - по одной).&lt;br /&gt;
 &lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ её сложность будет равна &amp;lt;math&amp;gt;2&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;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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 2). &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;
В случае, когда требуется решение нескольких СЛАУ с одной и той же матрицей, левую ветвь вычислений (см. рисунки с графом алгоритма) можно не повторять. Это связано с тем, что &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложение матрицы системы не нужно перевычислять. Тогда будет более предпочтителен вариант с заменой делений.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В зависимости от способа хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов) и способа хранения вычисляемых коэффициентов (на месте уже использованных элементов матрицы либо отдельно) возможны различные реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
Приведем пример подпрограммы на языке Fortran, реализующей прогонку, где все элементы матрицы хранятся в одном массиве, причём соседние элементы матричной строки размещаются рядом, а вычисляемые коэффициенты --- на месте элементов исходной матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine progm (a,x,N)&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      do 10 i=1,N-1&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(3,i)=-a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
  10  continue&lt;br /&gt;
      a(2,N)=1./(a(2,N)+a(1,N)*a(2,N-1))&lt;br /&gt;
      x(N)=(x(N)-a(1,N)*x(N-1))*a(2,N) ! y N&lt;br /&gt;
      do 20 i=N-1,0,-1&lt;br /&gt;
        x(i)=a(3,i)*x(i+1)+x(i) ! y i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В Сети имеется много простых реализаций метода, например в [https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8 Викиучебник - Реализации алгоритмов - Метод прогонки]&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, которые необходимы для операций, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом углу&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, чтобы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;.&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для выполнения основных операций прогонки, вычисляются в непосредственно предшествующим им операциях, возможность использования суперскалярности вычислительных ядер процессоров практически сводится на нет, что резко ухудшает эффективность выполнения прогонки даже на современных однопроцессорных и одноядерных системах.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_1.png|thumb|center|700px|Рисунок 3. Прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта прогонки. Данный профиль состоит из обращений к 5 массивам – трем диагоналям матрицы, вектору правых частей и результирующему вектору. Исходя из общего профиля, можно увидеть, что программа состоит из двух этапов – на первом выполняется последовательный перебор элементов 4-х массивов, на втором – также последовательный перебор, только в обратном порядке.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
Однако при более детальном рассмотрении можно заметить, что профиль устроен несколько сложнее (рис. 4). Для некоторых массивов на каждом шаге выполняется по несколько очень близких обращений, что приводит к улучшению как пространственной, так и временной локальности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, общий профиль обладает высокой пространственной локальностью (поскольку здесь доминируют последовательные переборы элементов) и средней временной (поскольку некоторые элементы сразу используются повторно).&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal/tridiagonal.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 5 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Для данной программы значения daps является достаточно неожиданным. Согласно качественному анализу, локальность обращений в память в этом случае достаточно высока. Однако daps оценивает производительность работы с памятью ниже, чем для теста RandomAccess! Такое различие между локальностью и производительностью встречается нечасто.&lt;br /&gt;
&lt;br /&gt;
При детальном рассмотрении исходного кода выяснились две причины такого поведения. Во-первых, итерации основного цикла являются зависимыми по памяти, то есть на очередной итерации используются данные, посчитанные на предыдущей. Похоже, что в данном случае эта зависимость значительно снижает эффективность работы с памятью, в то время как с точки зрения локальности данный случай является достаточно неплохим.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что одна из операций деления неожиданно существенно замедляет выполнение программы. При замене этой операции на умножение время выполнения уменьшается в 2.5 раза, при этом ассемблерный код двух вариантов программы выглядел идентично (за исключением очевидной замены одной команды деления на команду умножения). &lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_daps.png|thumb|center|700px|Рисунок 5. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Такие особенности программы не отражаются в ее свойствах локальности, что и привело к такому существенному разрыву между оценкой локальности и производительностью работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, и тем лучше локальность алгоритма. &lt;br /&gt;
&lt;br /&gt;
На рисунке 6 приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). В данном случае все предыдущие выводы подтверждаются – локальность оказывается достаточно высокой, что и было замечено согласно качественной оценке локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_cvg.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из анализа графа алгоритма, его (без существенных модификаций) практически невозможно распараллелить. Поэтому есть два способа использования прогонок для параллельных вычислительных систем: либо разбивать задачу, где используются прогонки, так, чтобы их было достаточно много, например, так, чтобы на каждую из прогонок приходился 1 процессор (1 ядро), либо использовать вместо прогонки её параллельные варианты (циклическую редукцию, последовательно-параллельные варианты и т.п.).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой прогонки, как полностью непараллельного алгоритма, говорить не имеет смысла. Однако необходимо отметить, что анализ масштабируемости параллельных вариантов прогонки должен проводиться относительно однопроцессорной реализации описанного классического варианта прогонки, а не относительно однопроцессорных расчетов для её параллельных вариантов.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведенных экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.019%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0255%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Tridiag Perf.png|thumb|center|700px|Рисунок 7. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Tridiag eff.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Малая эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiag/tridiagonal.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу существенно последовательной природы алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Прогонка - метод для архитектуры классического, фон-неймановского типа, непригодный даже для эффективной загрузки одноядерных систем, поддерживающих суперскалярность. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует использовать какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный вариант]].&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм прогонки является настолько простым, что, несмотря на его &amp;quot;дежурное&amp;quot; присутствие в стандартных пакетах программ решения задач линейной алгебры, большинство использующих его исследователей-прикладников часто пишут соответствующий фрагмент программы самостоятельно. Однако надо отметить, что, как правило, метод прогонки в пакетах реализуют не в его &amp;quot;чистом виде&amp;quot;, а в виде пары &amp;quot;разложение на две двухдиагональные матрицы&amp;quot; и &amp;quot;решение СЛАУ с предварительно факторизованной трёхдиагональной матрицей&amp;quot;. Так обстоит дело, например, в пакете SCALAPACK и его предшественниках.&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3266</id>
		<title>Прогонка, точечный вариант</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9F%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B0,_%D1%82%D0%BE%D1%87%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B2%D0%B0%D1%80%D0%B8%D0%B0%D0%BD%D1%82&amp;diff=3266"/>
		<updated>2016-01-27T15:38:14Z</updated>

		<summary type="html">&lt;p&gt;Икрамов: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Прогонка для трёхдиагональной матрицы,&amp;lt;br /&amp;gt; точечный вариант&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;8n-7&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;5n-4&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;4n-2&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|А.В.Фролов]], [[Участник: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; - один из вариантов метода исключения неизвестных, применяемого к решению СЛАУ&amp;lt;ref name=&amp;quot;VOLA&amp;quot;&amp;gt;Воеводин В.В. Вычислительные основы линейной алгебры. М.: Наука, 1977.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;MIV&amp;quot;&amp;gt;Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления. М.: Наука, 1984.&amp;lt;/ref&amp;gt; вида &amp;lt;math&amp;gt;Ax = b&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;. Суть метода состоит в исключении из уравнений неизвестных, сначала - сверху вниз - под диагональю, а затем - снизу вверх - над диагональю. Вариант, когда СЛАУ &amp;quot;проходится&amp;quot; наоборот, снизу вверх и обратно вниз - &#039;&#039;&#039;левая прогонка&#039;&#039;&#039; - принципиально ничем не отличается от рассматриваемого, поэтому нет смысла включать его отдельное описание.&lt;br /&gt;
&lt;br /&gt;
[[file:Progonka.png|thumb|right|200px|Рисунок 1. Граф алгоритма прогонки при n=8 без отображения входных и выходных данных. &#039;&#039;&#039;/&#039;&#039;&#039; - деление, &#039;&#039;&#039;&#039;&#039;f&#039;&#039;&#039;&#039;&#039; - операция &#039;&#039;&#039;&#039;&#039;a+bc&#039;&#039;&#039;&#039;&#039; или &#039;&#039;&#039;&#039;&#039;a-bc&#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;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N-1&amp;lt;/math&amp;gt;,  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = 1, 2, \cdots , N&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
после чего вычисляют решение с помощью обратного хода&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = \beta_{N+1}&amp;lt;/math&amp;gt;, &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\quad i = N-1, N-2, \cdots , 1, 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В литературе&amp;lt;ref name=&amp;quot;SETKI&amp;quot; /&amp;gt; указывается, что данные формулы эквивалентны вычислению одного из вариантов &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложения матрицы системы с последующим решением двухдиагональных систем посредством прямой и обратной подстановок.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма можно считать состоящим из двух частей - прямого и обратного хода прогонки. В прямом ходе вычислительное ядро составляют последовательности операций деления, умножения и сложения/вычитания. В обратном ходе в вычислительном ядре остаются только последовательности умножения и сложения. &lt;br /&gt;
[[file:ProgonkaInv.png|thumb|left|420px|Рисунок 2. Детальный граф алгоритма прогонки с однократным вычислением обратных чисел при n=4 без отображения входных и выходных данных. &#039;&#039;&#039;inv&#039;&#039;&#039; - вычисление обратного числа, &#039;&#039;&#039;mult&#039;&#039;&#039; - операция перемножения чисел. Серым цветом выделены операции, повторяющиеся при замене правой части СЛАУ]]&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;
Последовательность исполнения метода следующая: &lt;br /&gt;
&lt;br /&gt;
1. Инициализируется прямой ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{1} = b_{0}/c_{0}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{1} = f_{0}/c_{0} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Последовательно для всех i от 1 до N-1 выполняются формулы прямого хода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\alpha_{i+1} = b_{i}/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;, &lt;br /&gt;
 &lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i+1} = (f_{i}+a_{i}\beta_{i})/(c_{i}-a_{i}\alpha_{i})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
3. Инициализируется обратный ход прогонки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y_{N} = (f_{N}+a_{N}\beta_{N})/(c_{N}-a_{N}\alpha_{N})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Последовательно для всех i с убыванием от N-1 до 0 выполняются формулы обратного хода:&lt;br /&gt;
&amp;lt;math&amp;gt;y_{i} = \alpha_{i+1} y_{i+1} + \beta_{i+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В формулах прямого хода присутствуют пары делений на одно и то же выражение. Их можно заменить вычислением обратных чисел и последующим умножением на эти числа.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
	&lt;br /&gt;
* &amp;lt;math&amp;gt;2n-1&amp;lt;/math&amp;gt; делений,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; сложений/вычитаний,&lt;br /&gt;
* &amp;lt;math&amp;gt;3n-3&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Таким образом, при классификации по последовательной сложности, прогонка относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Информационный граф прогонки представлен на рис.1. Как следует из анализа графа, он является практически последовательным, при выполнении прямого хода две ветви (левая - разложение матрицы, центральная - решение первой из двухдиагональных систем) могут выполняться параллельно друг другу. Правая ветвь соответствует обратному ходу. Из рисунка видно, что не только математическая суть обработки элементов векторов, но даже структура графа алгоритма и направление потоков данных в нём вполне соответствуют названию &amp;quot;обратный ход&amp;quot;.&lt;br /&gt;
Вариант с заменой делений сводится к графу, который изображён на рис.2.&lt;br /&gt;
&lt;br /&gt;
=== Описание ресурса параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для выполнения прогонки в трёхдиагональной СЛАУ из n уравнений с n неизвестными в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов делений (в каждом из ярусов, кроме одного, по 2 деления),&lt;br /&gt;
* по &amp;lt;math&amp;gt;2n - 2&amp;lt;/math&amp;gt; ярусов умножений и сложений/вычитаний (в n-1 ярусах - по 2 операции, в n-1 - по одной).&lt;br /&gt;
 &lt;br /&gt;
Таким образом, при классификации по высоте ЯПФ, прогонка относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ её сложность будет равна &amp;lt;math&amp;gt;2&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;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_{i}&amp;lt;/math&amp;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;x_{i}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#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;
Соотношение последовательной и параллельной сложности, как хорошо видно, является &#039;&#039;константой&#039;&#039; (причём менее 2). &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;
В случае, когда требуется решение нескольких СЛАУ с одной и той же матрицей, левую ветвь вычислений (см. рисунки с графом алгоритма) можно не повторять. Это связано с тем, что &amp;lt;math&amp;gt;LU&amp;lt;/math&amp;gt;-разложение матрицы системы не нужно перевычислять. Тогда будет более предпочтителен вариант с заменой делений.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В зависимости от способов хранения матрицы СЛАУ (в виде одного массива с 3 строками или в виде 3 разных массивов) и способов хранения вычисляемых коэффициентов (на месте использованных уже элементов матрицы либо отдельно) возможны различные реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
Приведем пример подпрограммы на языке Fortran, реализующей прогонку, где все элементы матрицы таким образом,  в одном массиве, причём соседние по строке - рядом, а вычисляемые коэффициенты размещаются на месте исходных элементов матрицы. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;fortran&amp;quot;&amp;gt;&lt;br /&gt;
      subroutine progm (a,x,N)&lt;br /&gt;
      real a(3,0:N), x(0:N)&lt;br /&gt;
      a(2,0)=1./a(2,0)&lt;br /&gt;
      a(3,0)=-a(3,0)*a(2,0) ! alpha 1&lt;br /&gt;
      x(0)=x(0)*a(2,0) ! beta 1&lt;br /&gt;
      do 10 i=1,N-1&lt;br /&gt;
        a(2,i)=1./(a(2,i)+a(1,i)*a(2,i-1))&lt;br /&gt;
        a(3,i)=-a(3,i)*a(2,i) ! alpha i+1&lt;br /&gt;
        x(i)=(x(i)-a(1,i)*x(i-1))*a(2,i) ! beta i+1&lt;br /&gt;
  10  continue&lt;br /&gt;
      a(2,N)=1./(a(2,N)+a(1,N)*a(2,N-1))&lt;br /&gt;
      x(N)=(x(N)-a(1,N)*x(N-1))*a(2,N) ! y N&lt;br /&gt;
      do 20 i=N-1,0,-1&lt;br /&gt;
        x(i)=a(3,i)*x(i+1)+x(i) ! y i&lt;br /&gt;
  20  continue&lt;br /&gt;
      return&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В Сети имеется много простых реализаций метода, например в [https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%BF%D1%80%D0%BE%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8 Викиучебник - Реализации алгоритмов - Метод прогонки]&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
Как видно по графу алгоритма, локальность данных по пространству хорошая - все аргументы, которые необходимы для операций, вычисляются &amp;quot;рядом&amp;quot;. Однако по времени локальность вычислений не столь хороша. Если данные задачи не помещаются в кэш, то вычисления в &amp;quot;верхнем левом углу&amp;quot; СЛАУ будут выполняться с постоянными промахами кэша. Отсюда может следовать одна из рекомендаций прикладникам, использующим прогонку, - нужно организовать все вычисления так, чтобы прогонки были &amp;quot;достаточно коротки&amp;quot; для помещения данных в кэш.&lt;br /&gt;
&lt;br /&gt;
При этом, однако, прогонка относится к таким последовательным алгоритмам, в которых локальность вычислений настолько велика, что является даже излишней&amp;lt;ref&amp;gt;Фролов А.В., Антонов А.С., Воеводин Вл.В., Теплов А.М. Сопоставление разных методов решения одной задачи по методике проекта Algowiki // Подана на конференцию &amp;quot;Параллельные вычислительные технологии (ПаВТ&#039;2016)&amp;quot;.&amp;lt;/ref&amp;gt;. Из-за того, что данные, необходимые для вычислений основных операций алгоритма прогонки, вычисляются в её процессе операциями, непосредственно предшествующими им, возможности вычислительных ядер процессоров по использованию своей [[Глоссарий#Суперскалярность|суперскалярности]] практически сводятся на нет, что резко ухудшает эффективность выполнения прогонки даже на современных однопроцессорных и одноядерных системах.&lt;br /&gt;
&lt;br /&gt;
==== Локальность реализации алгоритма ====&lt;br /&gt;
===== Структура обращений в память и качественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_1.png|thumb|center|700px|Рисунок 3. Прогонка, точечный вариант. Общий профиль обращений в память]]&lt;br /&gt;
&lt;br /&gt;
На рис. 3 представлен профиль обращений в память для реализации точечного варианта прогонки. Данный профиль состоит из обращений к 5 массивам – трем диагоналям матрицы, вектору правых чисел и результирующему вектору. Исходя из общего профиля, можно увидеть, что программа состоит из двух этапов – на первом выполняется последовательный перебор элементов 4-х массивов, на втором – также последовательный перебор, только в обратном порядке.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_2.png|thumb|center|500px|Рисунок 4. Фрагмент общего профиля (выделенный зеленым цветом на рис. 3)]]&lt;br /&gt;
&lt;br /&gt;
Однако при более детальном рассмотрении можно заметить, что профиль устроен несколько сложнее (рис. 4). Для некоторых массивов на каждом шаге выполняется по несколько очень близких обращений, что приводит к улучшению как пространственной, так и временной локальности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, общий профиль обладает высокой пространственной локальностью (поскольку здесь доминируют последовательные переборы элементов) и средней временной (поскольку некоторые элементы сразу используются повторно).&lt;br /&gt;
&lt;br /&gt;
===== Количественная оценка локальности =====&lt;br /&gt;
&lt;br /&gt;
Основной фрагмент реализации, на основе которого были получены количественные оценки, приведен [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/benchmarks/tridiagonal/tridiagonal.h здесь] (функция Kernel). Условия запуска описаны [http://git.parallel.ru/shvets.pavel.srcc/locality/blob/master/README.md здесь].&lt;br /&gt;
&lt;br /&gt;
Первая оценка выполняется на основе характеристики daps, которая оценивает число выполненных обращений (чтений и записей) в память в секунду. Данная характеристика является аналогом оценки flops применительно к работе с памятью и является в большей степени оценкой производительности взаимодействия с памятью, чем оценкой локальности. Однако она служит хорошим источником информации, в том числе для сравнения с результатами по следующей характеристике cvg.&lt;br /&gt;
&lt;br /&gt;
На рисунке 5 приведены значения daps для реализаций распространенных алгоритмов, отсортированные по возрастанию (чем больше daps, тем в общем случае выше производительность). Для данной программы значения daps является достаточно неожиданным. Согласно качественному анализу, локальность обращений в память в этом случае достаточно высока. Однако daps оценивает производительность работы с памятью значение ниже, чем для теста RandomAccess! Такое различие между локальностью и производительностью встречается нечасто.&lt;br /&gt;
&lt;br /&gt;
При детальном рассмотрении исходного кода выяснились две причины такого поведения. Во-первых, итерации основного цикла являются зависимыми по памяти, то есть на очередной итерации используются данные, посчитанные на предыдущей. Похоже, что в данном случае эта зависимость значительно снижает эффективность работы с памятью, в то время как с точки зрения локальности данный случай является достаточно неплохим.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что одна из операций деления неожиданно существенно замедляет выполнение программы. При замене этой операции на умножение время выполнения уменьшается в 2.5 раза, при этом ассемблерный код двух вариантов программы выглядел идентично (за исключением очевидной замены одной команды деления и команду умножения). &lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_daps.png|thumb|center|700px|Рисунок 5. Сравнение значений оценки daps]]&lt;br /&gt;
&lt;br /&gt;
Такие особенности программы не отражаются в ее свойствах локальности, что и привело к такому существенному разрыву между оценкой локальности и производительностью работы с памятью.&lt;br /&gt;
&lt;br /&gt;
Вторая характеристика – cvg – предназначена для получения более машинно-независимой оценки локальности. Она определяет, насколько часто в программе необходимо подтягивать данные в кэш-память. Соответственно, чем меньше значение cvg, тем реже это нужно делать, и тем лучше локальность алгоритма. &lt;br /&gt;
&lt;br /&gt;
На рисунке 6 значения приведены значения cvg для того же набора реализаций, отсортированные по убыванию (чем меньше cvg, тем в общем случае выше локальность). В данном случае все предыдущие выводы подтверждаются – локальность оказывается достаточно высокой, что и было замечено согласно качественной оценке локальности.&lt;br /&gt;
&lt;br /&gt;
[[file:tridiagonal_cvg.png|thumb|center|700px|Рисунок 6. Сравнение значений оценки cvg]]&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как видно из анализа графа алгоритма, его (без существенных модификаций) практически невозможно распараллелить. Поэтому есть два способа использования прогонок для параллельных вычислительных систем: либо разбивать задачу, где используются прогонки, так, чтобы их было достаточно много, чтобы на каждую из прогонок приходился 1 процессор (1 ядро), либо использовать вместо прогонки её параллельные варианты (циклическую редукцию, последовательно-параллельные варианты и т.п.).&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
О масштабируемости самой прогонки, как полностью непараллельного алгоритма, говорить не имеет смысла. Однако необходимо отметить, что анализ масштабируемости параллельных вариантов прогонки должен проводиться относительно однопроцессорной реализации описанного классического варианта прогонки, а не относительно однопроцессорных расчетов для её параллельных вариантов.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости реализации алгоритма согласно [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &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;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров 1;&lt;br /&gt;
*	размер области [10240 : 1024000] с шагом 10240.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0.019%;&lt;br /&gt;
*	максимальная эффективность реализации 0.0255%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации алгоритма в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:Tridiag Perf.png|thumb|center|700px|Рисунок 7. Реализация алгоритма. Изменение производительности в зависимости от размера вектора.]]&lt;br /&gt;
[[file:Tridiag eff.png|thumb|center|700px|Рисунок 8. Реализация алгоритма. Изменение эффективности в зависимости от размера вектора.]]&lt;br /&gt;
&lt;br /&gt;
Малая эффективность, по-видимому, связана с избыточной локальностью, описанной в разделе о [[#Локальность данных и вычислений|локальности данных и вычислений]].&lt;br /&gt;
&lt;br /&gt;
Исследованная [http://git.algowiki-project.org/Teplov/Scalability/blob/master/tridiag/tridiagonal.h реализация алгоритма]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
В силу последовательности алгоритма и его избыточной локальности, исследование его динамических характеристик представляется малоценным и потому не проводилось.&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
Прогонка - метод для архитектуры классического, фон-неймановского типа, непригодный даже для эффективной загрузки одноядерных систем, поддерживающих суперскалярность. Для распараллеливания решения СЛАУ с трёхдиагональной матрицей следует использовать какой-либо её параллельный заменитель, например, наиболее распространённую [[Метод циклической редукции|циклическую редукцию]], или уступающий ей по критическому пути графа, но имеющий более регулярную структуру графа новый [[Последовательно-параллельный вариант решения трёхдиагональной СЛАУ с LU-разложением и обратными подстановками|последовательно-параллельный вариант]].&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм прогонки является настолько простым, что, несмотря на его &amp;quot;дежурное&amp;quot; присутствие в стандартных пакетах программ решения задач линейной алгебры, большинство использующих его исследователей-прикладников часто пишут соответствующий фрагмент программы самостоятельно. Однако надо отметить, что, как правило, метод прогонки в пакетах реализуют не в его &amp;quot;чистом виде&amp;quot;, а в виде пары &amp;quot;разложение на две двухдиагональные матрицы&amp;quot; и &amp;quot;решение СЛАУ с предварительно факторизаванной трёхдиагональной матрицей&amp;quot;, как, например, в пакете SCALAPACK и его предшественниках.&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;/div&gt;</summary>
		<author><name>Икрамов</name></author>
	</entry>
</feed>