<?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=Evgeny+Mortikov</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=Evgeny+Mortikov"/>
	<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/Evgeny_Mortikov"/>
	<updated>2026-10-23T01:01:07Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=21056</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%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=21056"/>
		<updated>2016-12-16T13:12:56Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Dan|Evgeny Mortikov}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n).&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В силу того, что определить разреженную матрицу строго не получается, то разреженными матрицами можно считать именно те, для которых применение специализированных алгоритмов обработки и/или хранения является оправданным.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен (имеется ввиду, что по индексу строки мы получаем информацию из массива pointer[] о расположении &#039;&#039;идущих по порядку элементов этой строки&#039;&#039; в массиве values[], а чтобы получить все элементы какого-то конкретного столбца придется пройтись по всему вектору pointer[]). Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N \cdot M  (N \le M)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;NZ-N&amp;lt;/math&amp;gt; сложений(случай с нулевыми строками рассматривать не будем).&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ-N&amp;lt;/math&amp;gt; сложений.&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ-N&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&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;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&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;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N\cdot M  (N \le M)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&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;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации умножения разреженной матрицы на вектор. Исследование проводилось на вычислительном комплексе [http://hpc.cmc.msu.ru/bgp Blue Gene/P]&amp;lt;ref&amp;gt; Blue Gene/P http://hpc.cmc.msu.ru/bgp&amp;lt;/ref&amp;gt;. Вычисления проводились с помощью следующего программного [https://www.dropbox.com/s/gx0s5r0jg58y8wa/main.c кода]&amp;lt;ref&amp;gt;Sparse matrix-vector MPI multiplication &amp;lt;/ref&amp;gt;. &lt;br /&gt;
Матрицы генерировались случайным образом. Размерность матрицы в рассматриваемом эксперименте роли не играла, так генерировался сразу строчный формат хранения матрицы. &lt;br /&gt;
&lt;br /&gt;
На следующем рисунке показана зависимость времени выполнения алгоритма от числа используемых процессоров и количества ненулевых элементов матрицы. Можно заметить, что скорость вычисления при переходе с последовательной на параллельную версию возросла значительно. Однако, дальнейшее увеличение числа вычислительных устройств не дает сильного прироста производительности. Это объясняется быстрым ростом накладных расходов на организацию параллельного выполнения.&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_more_points.png|thumb|center|1000px|Рис.3 Умножение разреженной матрицы на вектор. Масштабируемость]]&lt;br /&gt;
&lt;br /&gt;
На рисунке ниже изображен график эффективности в зависимости от числа процессоров и размера задачи. Можно заметить небольшой всплеск эффективности при использовании 64 процессоров.&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_eff_new.png|thumb|center|1000px|Рис.4 Умножение разреженной матрицы на вектор. Эффективность]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математический пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%91%D0%BE%D0%B1%D1%86%D0%BE%D0%B2_%D0%91%D0%BE%D1%80%D0%B8%D1%81/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D0%BB%D0%B0_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%BE_%D1%81%D0%B3%D1%83%D1%89%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%D1%81%D1%8F_%D1%81%D0%B5%D1%82%D0%BA%D0%B8&amp;diff=20964</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%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%91%D0%BE%D0%B1%D1%86%D0%BE%D0%B2_%D0%91%D0%BE%D1%80%D0%B8%D1%81/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D0%BB%D0%B0_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%BE_%D1%81%D0%B3%D1%83%D1%89%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%D1%81%D1%8F_%D1%81%D0%B5%D1%82%D0%BA%D0%B8&amp;diff=20964"/>
		<updated>2016-12-14T22:58:51Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|ASA|Evgeny Mortikov}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt; O\left( n \right) &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - количество подотрезков, на которые разбился исходный отрезок&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;+ 1&amp;lt;/math&amp;gt; функция &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; переменной&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; число)&lt;br /&gt;
}}&lt;br /&gt;
Автор статьи: [[Участник:Stalles|Бобцов Борис]] (группа 619)&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;I = \int_a^b{f(x)dx}&amp;lt;/math&amp;gt; от непрерывной функции &amp;lt;math&amp;gt;f(x)&amp;lt;/math&amp;gt;. Если может быть найдена первообразная &amp;lt;math&amp;gt;F(x)&amp;lt;/math&amp;gt; подынтегральной функции, то по формуле Ньютона-Лейбница:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\int_a^b{f(x)dx} = F(b) - F(a). &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если же первообразная не может быть найдена, то для вычисления интеграла прибегают к приближённым формулам, точность которых может быть сделана сколь угодно большой.&lt;br /&gt;
&lt;br /&gt;
Приближённые методы вычисления определённого интеграла в большинстве случаев основаны на том, что определённый интеграл численно равен площади криволинейной трапеции, ограниченной кривой &amp;lt;math&amp;gt; y =f(x)&amp;lt;/math&amp;gt;, сегментом &amp;lt;math&amp;gt; \left[ a,b \right] &amp;lt;/math&amp;gt; оси &amp;lt;math&amp;gt;Ox&amp;lt;/math&amp;gt; и вертикальными прямыми &amp;lt;math&amp;gt;x = a&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;x = b&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Идея данных методов заключается в приближении исходной кривой новой, достаточно близкой к старой, кривой. В качестве этой новой кривой подбирают такую, для которой площадь криволинейной трапеции подсчитывается просто. В зависимости от выбора новой кривой мы получим ту или иную приближённую формулу интегрирования.&lt;br /&gt;
&lt;br /&gt;
Разбивая сегмент интегрирования на несколько достаточно малых частей, на каждом из полученных маленьких сегментов мы можем приблизить интегрируемую функцию прямой. Тем самым мы заменим криволинейную трапецию прямолинейной, формула площади которой проста для вычисления.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
==== Метод трапеций ====&lt;br /&gt;
Будем рассматривать проблему вычисления значения определенного интеграла с некоторой заданной точностью &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;I(a,b) = \int_a^b{f(x)dx}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть на отрезке &amp;lt;math&amp;gt; [a,b] &amp;lt;/math&amp;gt; задана равномерная сетка, содержащая &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt; узел:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; x_{i} = a + \frac{(b - a)} {n} i,   i = 0,...,n &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда, согласно методу трапеций, можно численно найти определенный интеграл от функции &amp;lt;math&amp;gt; f (x) &amp;lt;/math&amp;gt; на отрезке &amp;lt;math&amp;gt;[a,b]&amp;lt;/math&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \int_a^b{f(x)dx} = \frac{b - a}{n} \left( \frac{f(x_0)}{2} + \sum^{n-1}_{i=1} {f(x_i)}  + \frac{f(x_n)}{2} \right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Будем полагать значение &amp;lt;math&amp;gt; I &amp;lt;/math&amp;gt; найденным с точностью &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;, если выполнено условие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; |I_{n_1} - I_{n_2}| \leq \epsilon |I_{n_2}|, n_1 &amp;gt; n_2, &amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;  n_1 &amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt; n_2 &amp;lt;/math&amp;gt; - количество узлов, образующих две разные сетки.&lt;br /&gt;
&lt;br /&gt;
==== Метод рекурсивного деления ====&lt;br /&gt;
&lt;br /&gt;
Метод трапеций обладает следующими недостатками:&lt;br /&gt;
* в некоторых точках значение функции будет вычисляться несколько раз;&lt;br /&gt;
* на всём интервале интегрирования используется равномерная сетка, тогда как число точек, необходимых для достижения заданной точности, зависит от вида функции и может сильно различаться на разных участках сегмента интегрирования.&lt;br /&gt;
&lt;br /&gt;
Метод рекурсивного деления был придуман, чтобы избежать этих недостатков. Суть метода заключается в рекурсивном вызове себя до момента, пока мы не достигнем нужной точности:&lt;br /&gt;
&amp;lt;math&amp;gt; I(a,b) = IntTrap(a, b, f(a), f(b)) = IntTrap(a, (b - a) / 2, f(a), f((b - a) / 2)) + IntTrap((b - a) / 2, b, f((b - a) / 2), f(b)) = ...  &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Однако можно заметить, что координаты концов обрабатываемых отрезков  хранятся в программном стеке процесса &amp;lt;math&amp;gt;IntTrap() &amp;lt;/math&amp;gt;, и недоступны программисту. Имеется в виду тот факт, что при рекурсивном вызове процесс, вызвавший IntTrap для двух подотрезков, будет ожидать завершения работы вызванных функций. При этом выполнять какую-то другую работу он не будет. При достаточно большой глубине рекурсии возникнет ситуация, когда много процессоров будут ожидать выполнения работы рекурсивных вызовов, сами при этом простаивая. При ограниченном числе процессоров это сильно замедлит выполнение программы, приблизив его к времени работы последовательного варианта. Однако, если учесть, что время порождения параллельных процессов существенно не равно нулю, время работы такой программы может стать даже больше времени выполнения последовательной версии.&lt;br /&gt;
&lt;br /&gt;
====Метод локального стека ====&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм использует массив данных, доступ к которым осуществляется по принципу стека - первым удаляется последний из добавленных элементов. Теперь у разных процессов есть возможность обрабатывать отрезки независимо друг от друга, так как у каждого процесса существует свой стек, и он работает только с отрезками, которые хранятся в нём. Поэтому не возникнет ситуации, когда один процесс не может продолжить свою работу из-за ожидания завершения другого процесса. В рассматриваемом алгоритме вместо стека можно было использовать и другие способы хранения заданий, например очередь. Стек выбран исключительно из соображений простоты реализации.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
В схеме реализации будет явно видно, что алгоритм реализуется при помощи цикла, внутри которого происходит подсчет текущих частичных сумм и проверка достигнутой точности. Сложность данного алгоритма зависит от количества проходов по циклу линейно, поэтому можно считать, что тело этого цикла и является вычислительным ядром данного алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
Как уже было замечено, алгоритм представляет собой три основные части, выполняющиеся в цикле. Сначала вычисляются частичные суммы на имеющемся отрезке, затем проверяется точность вычислений и, в случае, если точность недостаточна, вычисляются новые отрезки.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:123321.png]]&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Будем считать, что описана функция double f( double x ), возвращающая значение f(x) интегрируемой функции f в точке x.&lt;br /&gt;
&lt;br /&gt;
    double f( double x );&lt;br /&gt;
&lt;br /&gt;
    int sp = 0;       //указатель вершины стека&lt;br /&gt;
&lt;br /&gt;
    struct&lt;br /&gt;
    {&lt;br /&gt;
        double a;&lt;br /&gt;
        double b;&lt;br /&gt;
        double fa;&lt;br /&gt;
        double fb;&lt;br /&gt;
        double sab;&lt;br /&gt;
    } stk[1000];      //массив структур, в которых хранятся отложенные значения. 1000 может быть заменена на необходимое число&lt;br /&gt;
&lt;br /&gt;
    //операции доступа к данным стека&lt;br /&gt;
    #define STACK_IS_NOT_FREE ( sp &amp;gt; 0 )&lt;br /&gt;
&lt;br /&gt;
    void PUT_INTO_STACK( double a, double b, double fa, double fb, double sab )&lt;br /&gt;
    {&lt;br /&gt;
        stk[sp].a = a;&lt;br /&gt;
        stk[sp].b = b;&lt;br /&gt;
        stk[sp].fa = fa;&lt;br /&gt;
        stk[sp].fb = fb;&lt;br /&gt;
        stk[sp].sab = sab;&lt;br /&gt;
        ++sp;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void GET_FROM_STACK( double&amp;amp; a, double&amp;amp; b, double&amp;amp; fa, double&amp;amp; fb, double&amp;amp; sab )&lt;br /&gt;
    {&lt;br /&gt;
        --sp;&lt;br /&gt;
        a = stk[sp].a;&lt;br /&gt;
        b = stk[sp].b;&lt;br /&gt;
        fa = stk[sp].fa;&lt;br /&gt;
        fb = stk[sp].fb;&lt;br /&gt;
        sab = stk[sp].sab;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //основная функция &lt;br /&gt;
    int IntTrap(a, b)&lt;br /&gt;
    {&lt;br /&gt;
        double I = 0;        //значение интеграла&lt;br /&gt;
        double fa = f( a );  //значение функции &amp;lt;math&amp;gt;y = f(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&lt;br /&gt;
        double fb = f( b );  //значение функции &amp;lt;math&amp;gt;y = f(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt;&lt;br /&gt;
        double fc = 0;&lt;br /&gt;
        double c = 0;        //середина отрезка интегрирования&lt;br /&gt;
        double sab = 0;      //&lt;br /&gt;
        double sac = 0;      //&lt;br /&gt;
        double scb = 0;      //&lt;br /&gt;
        double sabc = 0;     //переменные для подсчёта текущих сумм&lt;br /&gt;
        sab = ( fa + fb ) * ( b - a ) / 2;&lt;br /&gt;
        while( 1 )&lt;br /&gt;
        {&lt;br /&gt;
            c = ( a + b ) / 2;&lt;br /&gt;
            fc = f( c );&lt;br /&gt;
            sac = ( fa + fc ) * ( c - a ) / 2;&lt;br /&gt;
            scb = ( fc + fb ) * ( b - c ) / 2;&lt;br /&gt;
            sabc = sac + scb;&lt;br /&gt;
            if( abs( sab - sabc ) &amp;gt; &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; * abs ( sabc ) ) //&amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; - заданная точность&lt;br /&gt;
            {&lt;br /&gt;
                PUT_INTO_STACK( a, c, fa, fc, sac );&lt;br /&gt;
                a = c; &lt;br /&gt;
                fa = fc;&lt;br /&gt;
                sab = scb;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                I += sabc;&lt;br /&gt;
                if( STACK_IS_NOT_FREE )&lt;br /&gt;
                {&lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
                GET_FROM_STACK( a, b, fa, fb, sab );&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return I;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Работа со стеком происходит через операции доступа к данным. В основной функции в цикле происходит вычисление частичных сумм sac и scb, затем проверяется точность if( abs( sab - sacb ) &amp;gt;&amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; * abs ( sacb ) ). В случае достижения необходимой точности частичные суммы добавляются к значению интеграла I, если отрезков не осталось, то программа завершает работу, иначе из стека выгружается следующий отрезок. Если точность не достигнута, то правый полуотрезок загружается в стек, а левый полуотрезок устанавливается как текущий для следующей итерации цикла.&lt;br /&gt;
&lt;br /&gt;
Когда в стеке не останется отрезков, это будет означать, что программа рассчитала все отрезки до точки a включительно, и возвращает значение I как приближённое значение интеграла.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
Пусть для работы алгоритма было необходимо разбить отрезок &amp;lt;math&amp;gt; \left[a, b\right] &amp;lt;/math&amp;gt; на сегменты &amp;lt;math&amp;gt; \left[a=x_0 , x_1\right], \left[a=x_1 , x_2\right],... \left[a=x_{n-1} , x_n = b\right] &amp;lt;/math&amp;gt;.&lt;br /&gt;
Так как каждый раз, когда нам приходится вычислять площадь трапеции на более коротком сегменте, мы делим отрезок пополам, получаем, что длина каждого отрезка равна &amp;lt;math&amp;gt; \left( x_i - x_{i - 1} \right) = \frac{b - a}{2^k} &amp;lt;/math&amp;gt; для некоторого натурального &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Назовём глубиной метода максимальное &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt; из всех &amp;lt;math&amp;gt; k_i : \left( x_i - x_{i - 1} \right) = \frac{b - a}{2^{k_i}} &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Очевидно, что для каждой функции &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; и для каждой точности &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt; глубина алгоритма будет разной. То есть можно считать, что &amp;lt;math&amp;gt; k = k(f(x), \epsilon). &amp;lt;/math&amp;gt; Также понятно, что, если &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;- глубина алгоритма при фиксированных &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;, то максимально возможное количество полученных отрезков, для которых считалась частичная сумма, и количество точек на отрезке &amp;lt;math&amp;gt; \left[a, b\right] &amp;lt;/math&amp;gt; равны соответственно &amp;lt;math&amp;gt; 2^k &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; 2^k + 1 &amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt; k_i = k, i = 1,2,...,n &amp;lt;/math&amp;gt;. В этом худшем с точки зрения количества операций случае алгоритм прокрутит цикл while( 1 ) &amp;lt;math&amp;gt; 1 + 2 + 4 + ... + 2^k = (2^{k + 1}-1) &amp;lt;/math&amp;gt;   раз.&lt;br /&gt;
&lt;br /&gt;
Если не учитывать при расчёте сложности операции работы с памятью, а только сложения/вычитания и умножения*деления, получим, что за каждый выполненный цикл while( 1 ) алгоритм выполняет 7 сложений и 6 умножений. Итого получаем в худшем случае &amp;lt;math&amp;gt; 7*2^k &amp;lt;/math&amp;gt; сложений и &amp;lt;math&amp;gt; 6*2^k &amp;lt;/math&amp;gt; умножений. Кроме этого, алгоритм посчитает значение &amp;lt;math&amp;gt; f(x) &amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt; точках. При этом понятно, что &amp;lt;math&amp;gt; k \leq log(n). &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Получаем, что при разбиении исходного отрезка на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; подотрезков получаем глубину алгоритма &amp;lt;math&amp;gt; k \leq log(n) &amp;lt;/math&amp;gt; и  сложность алгоритма &amp;lt;math&amp;gt; O\left( n + 2^{log n} \right) = O\left( n + n \right) = O\left( n  \right) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При этом из всего вышесказанного сразу видно, что при достаточном количестве вычислительных ресурсов распараллеливания высота ярусно-параллельной формы параллельной программы будет равна глубине &amp;lt;math&amp;gt; k \leq log(n), &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;
[[Файл:Macromy.png|thumb|center|400px|Рис.1. Общая схема алгоритма ]]&lt;br /&gt;
&lt;br /&gt;
На Рис.1 изображена макроструктура алгоритма. На вход алгоритма подаётся функция, границы отрезка интегрирования и нужная точность. В предварительных вычислениях задаются границы первого отрезка и значения функции в них. Далее запускается операция обработки отрезка, в случае недостаточной точности повторяющаяся для двух подотрезков (и так далее, пока не будет достигнута нужная точность), на выход алгоритм выдаёт приближённое значение интеграла на заданном отрезке с необходимой точностью.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим процедуру обработки отрезка подробнее.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:Png граф.png|thumb|center|800px|Рис.2. Информационный граф одной итерации цикла (обработки одного отрезка) ]]&lt;br /&gt;
&lt;br /&gt;
На Рис.2 изображён информационный граф алгоритма обработки отрезка. Синими прямоугольниками изображены входные данные итерации цикла, внутри подписаны имена данных. Кругами изображены операции вычисления переменных, имена которых указаны внутри кругов. Зелёными овалами изображены прочие операции, выполняемые алгоритмом. После операции проверки точности алгоритм загружает правый отрезок в стек, а левый настраивает на дальнейшую обработку, если точность не достигнута, иначе загружает новый отрезок из стека. Затем происходит суммирование текущей частичной суммы с полученными ранее. При отсутствии отрезков в стеке итерация завершается.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Представленный алгоритм обладает хорошим ресурсом параллелизма. В самом деле, пусть в нашем распоряжении есть доступный всем параллельным процессам список отрезков интегрирования, организованный в виде стека. Назовём его глобальным стеком. Предположим, что перед запуском параллельных процессов в глобальный стек помещается единственная запись - координаты концов отрезка интегрирования - в дальнейшем - &amp;quot;отрезок&amp;quot;. Тогда возможно реализовать следующую схему алгоритма, выполняемую каждым из параллельных процессов:&lt;br /&gt;
&lt;br /&gt;
Пока в глобальном стеке есть отрезки:&lt;br /&gt;
*взять один отрезок из глобального стека;&lt;br /&gt;
*выполнить алгоритм локального стека, выполняя при записи в локальный стек следующие операции:&lt;br /&gt;
**если в локальном стеке есть несколько отрезков, а в глобальном стеке отрезки отсутствуют, то&lt;br /&gt;
***переместить часть отрезков из локального стека в глобальный;&lt;br /&gt;
**по исчерпании локального стека добавить полученную частичную сумму к общему значению интеграла.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: &lt;br /&gt;
* функция &amp;lt;math&amp;gt; y = f(x)&amp;lt;/math&amp;gt;;&lt;br /&gt;
* точность &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;;&lt;br /&gt;
* границы отрезка интегрирования &amp;lt;math&amp;gt; a, b.&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Функция может иметь любой вид представления, если это представление &amp;quot;константно&amp;quot;, то есть можно считать, что объём равен &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt;. В противном случае объем представления функции, подаваемый на вход, нельзя оценить. Кроме функции, на вход подаётся три вещественных числа, их объём - &amp;lt;math&amp;gt; 3 * sizeof( double ) = O\left( 1 \right) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: &lt;br /&gt;
* число &amp;lt;math&amp;gt;I &amp;lt;/math&amp;gt;, приближённо равное &amp;lt;math&amp;gt; \int_a^b{f(x)dx}&amp;lt;/math&amp;gt; с точностью &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На выход алгоритм выдаёт одно вещественное число, его объём - &amp;lt;math&amp;gt; sizeof( double ) = O\left( 1 \right) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм обладает большой вычислительной мощностью. Кроме того, у него имеется большой потенциал для распараллеливания.&lt;br /&gt;
&lt;br /&gt;
Алгоритм не обладает свойством детерминированности, так как в зависимости от специфических свойств графика входных функций может вести себя для них совершенно по-разному.&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности алгоритма высоко и равно приблизительно &amp;lt;math&amp;gt; \frac{n}{log(n)} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений === &lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Для распараллеливания программы был выбран алгоритм геометрического параллелизма. Весь отрезок интегрирования делился на равные части, количество которых было равно количеству процессов. Далее каждый процесс выполнял функцию &amp;lt;math&amp;gt; IntTrap(a_i, b_i) &amp;lt;/math&amp;gt; для своего отрезка &amp;lt;math&amp;gt; [ a_i, b_i ] &amp;lt;/math&amp;gt; независимо от других процессов. При таком алгоритме мало затрат на обмен данными между процессами, поэтому было решено воспользоваться только средствами библиотеки MPI. При запусках использовалась связка openmpi/1.8.4-gcc + gcc/5.2.0, реализация - тут -&amp;gt; [https://github.com/Stalles/superprak1 ссылка на реализацию.]&lt;br /&gt;
&lt;br /&gt;
Для оценки масштабируемости были произведены запуски на 1, 2, 4, 8, 16, 32, 48, 64, 80, 96, 112 и 128 процессах. В качестве тестируемой функции была выбрана функция &amp;lt;math&amp;gt;1/(x^2) * (sin(1/x))^2&amp;lt;/math&amp;gt;. Кроме того, для каждого количества процессов были произведены запуски при разной точности вычисления интеграла, от &amp;lt;math&amp;gt;10^{-5} &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;10^{-7} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На графиках, представленных ниже, отображена [[Глоссарий#Производительность|производительность]]  и [[Глоссарий#Эффективность распараллеливания|эффективность распараллеливания]] данного алгоритма в зависимости от изменяемых параметров запуска - точности вычислений и числа процессоров.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Png_mapoftime.png|thumb|center|800px|Рис.3. Время работы алгоритма в зависимости от числа процессов и точности вычислений ]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:Myefficiency.png|thumb|center|800px|Рис.4. Эффективность алгоритма в зависимости от числа процессоров и точности вычислений ]]&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов. Кроме того, видно, что при более,чем 40 процессов эффективность становится крайне низкой.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи (точности вычислений)&#039;&#039;&#039; — при увеличении точности вычислений и при постоянном числе процессов эффективность вычислений остаётся практически неизменяемой, очень медленно снижается. Это объясняется тем, что некоторые отрезки интегрирования имеют большую трудоёмкость из-за негладкости функции. Процессы, которым достались такие отрезки, и определяют время работы всей программы.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
На данный момент реализация алгоритма локального стека была указана только в книге Якобовского М.В., Кульковой Е.Ю. &amp;quot;Решение задач на многопроцессорных вычислительных системах с разделяемой памятью.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
# Шнейдер В. Е. и др. Краткий курс высшей математики. Учеб. пособие для втузов. М., «Высш. школа», 1972. 640 с.&lt;br /&gt;
# Якобовский М.В., Кулькова Е.Ю. Решение задач на многопроцессорных вычислительных системах с разделяемой памятью. - М.: СТАНКИН, 2004. – 30 c.&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lvs/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B_%D0%BB%D0%B8%D0%BD%D0%B5%D0%B9%D0%BD%D1%8B%D1%85_%D0%B0%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D1%83%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9_GMRES&amp;diff=20374</id>
		<title>Участник:Lvs/Итерационный метод решения системы линейных алгебраических уравнений GMRES</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lvs/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B_%D0%BB%D0%B8%D0%BD%D0%B5%D0%B9%D0%BD%D1%8B%D1%85_%D0%B0%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D1%83%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9_GMRES&amp;diff=20374"/>
		<updated>2016-12-08T16:33:27Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Dan|Evgeny Mortikov}}&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Метод минимальных невязок используется для решения систем линейных алгебраических уравнений с заданной точностью приближения. Приближённое решение в методе получается с помощью вектора в подпространстве Крылова. Для нахождения этого вектора используется алгоритм Арнольди, посредством которого матрица СЛАУ приводится к (верхней) хессенберговой форме. На основе этой формы происходит минимизация невязки.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
Дана система линейных алгебраических уравнений &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; - квадратная матрица размера &amp;lt;math&amp;gt;n \times n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляется последовательность приближённых решений уравнения &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt;, которая сходится к точному решению уравнения &amp;lt;math&amp;gt;x^*&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Подпространство Крылова размерности &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;, порожденное вектором &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; и матрицей &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; – линейное пространство&lt;br /&gt;
&amp;lt;math&amp;gt;K_m(A, v)&amp;lt;/math&amp;gt;, являющееся линейной оболочкой векторов &amp;lt;math&amp;gt;b, Ab, A^2b, ..., A^{m-1}b&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приближённое решение считается по формуле &amp;lt;math&amp;gt; x_m = Q_my_m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;Q_m&amp;lt;/math&amp;gt; - матрица размера &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;, составленная из векторов ортонормированного базиса пространства &amp;lt;math&amp;gt;K_m(A, v)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;y_m \in \mathbb{R}^m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итоговым считается решение, минимизирующее норму невязки (&amp;lt;math&amp;gt;||r||_2 = ||b - Ax_m||_2&amp;lt;/math&amp;gt;) с заданной точностью.&lt;br /&gt;
&lt;br /&gt;
Для вычисления векторов ортонормированного базиса используется алгоритм Арнольди:&lt;br /&gt;
# Значение первого вектора выбирается как &amp;lt;math&amp;gt;q_1 = b / ||b||&amp;lt;/math&amp;gt;&lt;br /&gt;
# Оставшиеся векторы &amp;lt;math&amp;gt;q_j, j = 2 .. n&amp;lt;/math&amp;gt; считаются по такому плану:&lt;br /&gt;
## Вычисляется вектор &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; путём умножения матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; на предыдущий вектор &amp;lt;math&amp;gt;q&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;z = Aq_{j-1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
## Вычисляются значения &amp;lt;math&amp;gt;h_{ij-1}&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1 .. j - 1&amp;lt;/math&amp;gt; как скалярное произведение вектора &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;q_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;h_{ij-1} = (z, q_i)&amp;lt;/math&amp;gt;. После каждого такого вычисления значение вектора &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; понижается на &amp;lt;math&amp;gt;h_{ij-1} q_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;z = z - h_{ij-1} q_i&amp;lt;/math&amp;gt;&lt;br /&gt;
## Затем вычисляется значение &amp;lt;math&amp;gt;h_{jj-1}&amp;lt;/math&amp;gt; как норма вектора &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;h_{jj-1} = ||z||&amp;lt;/math&amp;gt;. Алгоритм останавливается, если эта норма равна 0&lt;br /&gt;
## Если полученное значение нормы не равно 0, то &amp;lt;math&amp;gt;q_j = z /||z||&amp;lt;/math&amp;gt; (что эквивалентно &amp;lt;math&amp;gt;q_j = z /h_{jj-1}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Получаемые в процессе работы алгоритма векторы &amp;lt;math&amp;gt;q_1, q_2, ..., q_m&amp;lt;/math&amp;gt; образуют искомый ортонормированный базис Крыловского пространства &amp;lt;math&amp;gt;K_m(A, b)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Значения &amp;lt;math&amp;gt;h_{i,j}&amp;lt;/math&amp;gt; образуют верхнюю матрицу Хессенберга (обозначим как &amp;lt;math&amp;gt;H_m&amp;lt;/math&amp;gt;, размерность &amp;lt;math&amp;gt;m+1 \times m&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H_m = \begin{bmatrix}h_{11} &amp;amp; h_{12} &amp;amp; h_{13} &amp;amp;... &amp;amp; h_{1m-1} &amp;amp; h_{1m} \\ h_{21} &amp;amp; h_{22} &amp;amp; h_{23} &amp;amp; ... &amp;amp; h_{2m-1} &amp;amp; h_{2m} \\ 0 &amp;amp; h_{32} &amp;amp; h_{33} &amp;amp;...&amp;amp; h_{3m-1} &amp;amp; h_{3m} \\ ... &amp;amp; ... &amp;amp; ... &amp;amp; ... &amp;amp; ... &amp;amp; ... \\ 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; ... &amp;amp; h_{m m-1} &amp;amp; h_{mm} \\0 &amp;amp; 0 &amp;amp; 0 &amp;amp; ... &amp;amp; 0 &amp;amp; h_{m+1 m}\end{bmatrix}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вектор невязки задан уравнением &amp;lt;math&amp;gt;r_m = H_my_m - ||b - Ax_0||e_1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;x_0&amp;lt;/math&amp;gt; - вектор начального приближения. Минимизация второй нормы вектора невязки представляет из себя решение линейной задачи минимальных квадратов размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приближённое решение вычисляется по формуле &amp;lt;math&amp;gt; x_m = Q_my_m&amp;lt;/math&amp;gt; после нахождения соответствующего значения минимизирующего вторую невязку вектора. Сложность вычислений &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
Самая трудоёмкая и самая часто вызываемая операция в алгоритме - умножение матрицы на вектор. В первую очередь это связано с вычислением матрицы Хессенберга и ортонормированного базиса подпространства Крылова.&lt;br /&gt;
Число умножений матрицы на вектор: &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; в алгоритме Арнольди, K в выбранном алгоритме решения задачи минимальных квадратов и 1 в подсчёте результата.&lt;br /&gt;
Также в алгоритм входят &amp;lt;math&amp;gt;n*(n-1) / 2&amp;lt;/math&amp;gt; операций скалярного произведения.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
# Алгоритм Арнольди&lt;br /&gt;
# Решение линейной задачи минимальных квадратов&lt;br /&gt;
# Вычисление решения&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
    Вычислить ортонормированный базис размера m&lt;br /&gt;
    Вычислить минимальное приближение (минимальную норму вектора невязки)&lt;br /&gt;
    if (приближение &amp;lt; заданная точность)&lt;br /&gt;
        Вычислить результат&lt;br /&gt;
        return;&lt;br /&gt;
    else&lt;br /&gt;
        Повторить для m = m+1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Сложность вычислений собственных векторов на каждом шаге - &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Сложность решения задачи минимальных квадратов &amp;lt;math&amp;gt;O(m^2)&amp;lt;/math&amp;gt;, но при последовательном выполнении алгоритма можно понизить сложность до &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt; путём использования подсчитанных на прошлых итерациях значений.&lt;br /&gt;
&lt;br /&gt;
Сложность вычисления решения &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;, поэтому его целесообразно вычислять только в конце.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Основной ресурс параллелизма - умножение матрицы на вектор, поскольку является самым ресурсоёмким, но при этом умножать отдельные строки матрицы можно независимо друг от друга. Для этой операции информационный граф представлен на рисунке.&lt;br /&gt;
&lt;br /&gt;
[[file:GraphLvs2FM.jpg|thumb|center|700px|Рис.1. Информационный граф умножения матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
# Параллельное умножение матрицы на вектор выполняется в &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ярусов умножений и сложений.&lt;br /&gt;
# Операция вычисления скалярного произведения&lt;br /&gt;
# Шаги алгоритма Арнольди выполняются строго последовательно, однако последующее нахождение невязки можно выполнять параллельно с запуском следующего шага алгоритма.&lt;br /&gt;
# Сложность решения задачи минимальных квадратов зависит от используемого алгоритма. В отличие от последовательного метода данные, полученные на прошлых шагах здесь использовать нельзя.&lt;br /&gt;
# Вычисление результата выполняется один раз, его можно выполнить параллельно в &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ярусов умножений и сложений.&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;b&amp;lt;/math&amp;gt;, точность &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;. Объём: &amp;lt;math&amp;gt;n^2 + n + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; Вектор &amp;lt;math&amp;gt;x_m&amp;lt;/math&amp;gt;. Объём: &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
Теоретически на каждой итерации алгоритма сложность вычислений составляет &amp;lt;math&amp;gt;n + X&amp;lt;/math&amp;gt; операций умножения, где &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; - сложность алгоритма для решения задачи минимальных квадратов. Таким образом в худшем случае сложность будет примерно равна &amp;lt;math&amp;gt;n^2 + X*n + n&amp;lt;/math&amp;gt; операций умножения.&lt;br /&gt;
&lt;br /&gt;
Несмотря на то, что в теории итерации алгоритма можно выполнять параллельно после выполнения алгоритма Арнольди, на практике необходимая точность может быть достигнута раньше чем на n-й итерации, что потребует какого-нибудь способа прервать последующие итерации. Для избегания лишних вычислений возможно оптимально выполнять итерации алгоритма последовательно, вычисляя параллельно только векторно-матричные произведения.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
Для исследования масштабируемости алгоритма была использована параллельная реализация, найденная на просторах GitHub&amp;lt;ref&amp;gt;Parallel GMRES Algorithm for Solving Giant Sparse System of Linear Equations https://github.com/arrgasm/paraGMRES/&amp;lt;/ref&amp;gt;. Эта реализация использует многопроцессорное выполнение с общей памятью и вычисляет параллельно скалярное произведение и умножение матрицы на вектор. Программа была запущена на суперкомпьютере BlueGene на разреженной матрице размера 90448х90448 с 1921955 ненулевыми элементами, расположенными около главной диагонали. Параметрами запуска являются 100 итераций алгоритма и 10 перезапусков алгоритм (повторный запуск алгоритма с использованием решения, полученного на предыдущем запуске, в качестве начального приближения). График зависимости времени выполнения от числа процессоров представлен на рисунке 2.&lt;br /&gt;
[[file:PlotLvs1.png|thumb|center|400px|Рис 2. График зависимости времени выполнения от числа процессоров]]&lt;br /&gt;
График эффективности для полученного времени выполнения указан на рисунке 3.&lt;br /&gt;
[[file:PlotLvs2.png|thumb|center|400px|Рис 3. График зависимости эффективности реализации от числа процессоров]]&lt;br /&gt;
Параметры компиляции:&lt;br /&gt;
&amp;lt;code&amp;gt;mpixlc_r -qsmp=omp -O3&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметры запуска:&lt;br /&gt;
&amp;lt;code&amp;gt;gmres mat.mtx void 100 0 10&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Надо заметить, что для этой матрицы на таком числе итераций решения с заданной точностью найдено не было. Она была выбрана с целью показать масштабируемость алгоритма. На матрицах более малого размера решение находится быстро.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
Реализации алгоритма GMRES присутствуют во многих программных продуктах как части стандартных библиотек, например Matlab или DEFORM3D. Также существую отдельные библиотеки, например MGMRES для языка С++.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Тыртышников Е. Е. Методы численного анализа — М., Академия, 2007.&lt;br /&gt;
&lt;br /&gt;
[2] М. Дана, А. Г. Зыков, Х. Д. Икрамов Метод минимальных невязок для специального класса линейных систем с нормальными матрицами коэффициентов - Ж. вычисл. матем. и матем. физ., 2005, том 45, номер 11&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Blizn/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80.&amp;diff=19964</id>
		<title>Участник:Blizn/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор.</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Blizn/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80.&amp;diff=19964"/>
		<updated>2016-12-03T03:13:29Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|ASA|Evgeny Mortikov}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(l)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2l+m+n+1&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;
Выполнила: [[Участник:Blizn|И.В. Близнякова]] (611 группа).&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988.&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
* есть &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
* в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
* ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
* таково, что для данного алгоритма и вычислительной системы имеет смысл извлекать выгоду из наличия в ней нулей.&lt;br /&gt;
&lt;br /&gt;
=== Хранение разреженной матрицы ===&lt;br /&gt;
==== Формат RR(C)O ====&lt;br /&gt;
Рассмотрим сначала формат &#039;&#039;&#039;RR(C)O&#039;&#039;&#039;. Сокращенное название данного формата происходит от английского словосочетания &#039;&#039;&amp;quot;Row - wise Representation Complete and Ordered&amp;quot;&#039;&#039; (строчное представление, полное и упорядоченное). В данном формате вместо одного двумерного массива, используются три одномерных. Значения ненулевых элементов матрицы и соответствующие им столбцовые индексы хранятся в этом формате по строкам в двух массивах &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Массив указателей &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, используется для ссылки на компоненты массивов &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, с которых начинается описание очередной строки. Последняя компонента массива &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; содержит указатель первой свободной компоненты в массивах &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, т.е. равна числу ненулевых элементов матрицы, увеличенному на единицу. Здесь уместно привести пример.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим матрицу &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 0 \\&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 6 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
тогда ее представление в формате &#039;&#039;&#039;RR(C)O&#039;&#039;&#039; будет иметь вид:&lt;br /&gt;
   IA = [ 1 2 4 4 5 6 ]&lt;br /&gt;
   JA = [ 4 1 3 2 3 ]&lt;br /&gt;
   AN = [ 2 1 3 6 4 ]&lt;br /&gt;
Т.е. массив &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; содержит все не нулевые элементы исходной матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; номер столбца в котором находится соответствующий элемент из &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и наконец массив &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; содержит номер с которого начинается описание элементов в массивах &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Таким образом информация об элементах 2-ой строки матрицы хранится в элементах с &amp;lt;math&amp;gt;IA[2] = 2&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;IA[3] - 1 = 3&amp;lt;/math&amp;gt; включительно массивов &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Можно обратить внимание, что &amp;lt;math&amp;gt;IA[3] = IA[4] = 4&amp;lt;/math&amp;gt;, а это означает, что 3-я строка матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; нулевая.&lt;br /&gt;
&lt;br /&gt;
В общем случае описание &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;-й строки матрицы A хранится в компонентах с &amp;lt;math&amp;gt;IA[r]&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA[r + 1] - 1&amp;lt;/math&amp;gt; включительно массивов &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;IA[r + 1] = IA[r]&amp;lt;/math&amp;gt;, то это означает, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;-я строка нулевая. Количество элементов в массиве &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; на единицу больше, чем число строк исходной матрицы, а количество элементов в массивах &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; равно числу ненулевых элементов исходной матрицы.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют &#039;&#039;полным&#039;&#039;, поскольку представлена вся матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, &#039;&#039;упорядоченным&#039;&#039;, поскольку элементы каждой строки матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; хранятся в соответствии с возрастанием столбцовых индексов, и строчным, поскольку информация о матрице &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; указывается по строкам.&lt;br /&gt;
&lt;br /&gt;
Массивы &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; представляют портрет (структуру) матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, задаваемый как множество списков смежности ассоциированного с &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; графа. Если алгоритм, реализующий какую-либо операцию над разреженными матрицами, разбит на этапы символической обработки, на котором определяется портрет результирующей матрицы, и численной обработки, на котором определяются значения элементов результирующей матрицы, то массивы &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; заполняются на первом этапе, а массив &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; - на втором.&lt;br /&gt;
&lt;br /&gt;
==== Формат RR(C)U ====&lt;br /&gt;
 &lt;br /&gt;
Рассмотрим теперь формат &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Сокращенное название данного формата происходит от английского словосочетания &#039;&#039;&amp;quot;Row - wise Representation Complete and Unordered&amp;quot;&#039;&#039; (строчное представление, полное, но неупорядоченное). Формат &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; отличается от &#039;&#039;&#039;RR(C)O&#039;&#039;&#039; тем, что в данном случае соблюдается упорядоченность строк, но внутри каждой строки элементы исходных матриц могут храниться в произвольном порядке. Для матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; нашего примера вполне можно было бы использовать и строчное представление, полное, но неупорядоченное такое:&lt;br /&gt;
   IA = [ 1 2 4 4 5 6 ]&lt;br /&gt;
   JA = [ 4 3 1 2 3 ]&lt;br /&gt;
   AN = [ 2 1 3 6 4 ]&lt;br /&gt;
Такие неупорядоченные представления могут быть очень удобны в практических вычислениях. Результаты большинства матричных операций получаются неупорядоченными (например, операции вставки и удаления новых коэффициентов), а их упорядочение стоило бы значительных затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы их представления были упорядоченными.&lt;br /&gt;
&lt;br /&gt;
==== Замечания ====&lt;br /&gt;
&lt;br /&gt;
Несколько замечаний по поводу рассмотренных форматов представления:&lt;br /&gt;
# Очевидно, что представление матрицы в формате &#039;&#039;&#039;RR(C)O&#039;&#039;&#039; так же является и представлением в формате &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, но не наоборот.&lt;br /&gt;
# Из представления матрицы в формате &#039;&#039;&#039;RR(C)&#039;&#039;&#039; нельзя получить информацию о точном количестве столбцов исходной матрицы.&lt;br /&gt;
# Целесообразно (в вопросе экономии памяти) использовать представления &#039;&#039;&#039;RR(C)&#039;&#039;&#039; в случае, если матрица содержит значительное число нулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Умножение разреженной матрицы на вектор ===&lt;br /&gt;
&lt;br /&gt;
Важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &lt;br /&gt;
&lt;br /&gt;
Мы рассмотрим умножение разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; посредством массивов &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; на заполненный вектор-столбец.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Исходные данные: разреженная матрица общего вида &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;i = 1,...,n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j = 1,...,m&amp;lt;/math&amp;gt;). Заполненный вектор-столбец &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;j =1,...,m&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: заполненный вектор-столбец &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;i = 1,...,n&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Формулы метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{l_{i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;l_{i}&amp;lt;/math&amp;gt; - количество ненулевых элементов строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j(k)&amp;lt;/math&amp;gt; - индекс &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;-го ненулевого элемента матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
Вычислительное ядро последовательной версии умножения разреженной матрицы на вектор можно составить из множественных (всего их &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) вычислений скалярных произведений строк матрицы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{l_{i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Как записано и в [[#Вычислительное ядро алгоритма|описании ядра алгоритма]], основную часть метода составляют множественные (всего &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) вычисления сумм:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{l_{i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
которые могут вычисляться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Далее предполагаем, что разреженная матрица общего вида &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; хранится в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; посредством массивов &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;.&lt;br /&gt;
Последовательность исполнения метода следующая:&lt;br /&gt;
&lt;br /&gt;
Выполнять для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; &lt;br /&gt;
# &amp;lt;math&amp;gt;c_{i} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;math&amp;gt;IAA = IA[i]&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;math&amp;gt;IAB = IA[i + 1] - 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = IAA}^{IAB} AN[k]b_{JA[k]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
После этого (если &amp;lt;math&amp;gt;i \le n&amp;lt;/math&amp;gt;) происходит переход к шагу 1 с бо́льшим &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для умножения разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, размером &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt; на заполненный вектор &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;O(l)&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;O(l)&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Умножения и сложения составляют &#039;&#039;основную часть алгоритма&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам &amp;lt;math&amp;gt;O(l)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Опишем [[глоссарий#Граф алгоритма|граф алгоритма]]&amp;lt;ref&amp;gt;Воеводин В.В.  Математические основы параллельных вычислений// М.: Изд. Моск. ун-та, 1991. 345 с.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002. – 608 с.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Фролов А.В.. Принципы построения и описание языка Сигма. Препринт ОВМ АН N 236. М.: ОВМ АН СССР, 1989.&amp;lt;/ref&amp;gt; как аналитически, так и в виде рисунка.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
Первая группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Естественно введённые координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, принимая все целочисленные значения,&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = IA[i+1]-IA[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; - элемент &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;AN[IA_{i}+j-1]&amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; - элемент &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;b[IA_{i}+j-1]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;промежуточным данным&#039;&#039; алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Естественно введённые координаты области таковы: &lt;br /&gt;
* &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения,&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = IA[i+1]-IA[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;j = 1&amp;lt;/math&amp;gt; - результат срабатывания операции, соответствующей вершине из первой группы, с координатами &amp;lt;math&amp;gt;(i, j)&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;j &amp;gt; 1&amp;lt;/math&amp;gt; - результат срабатывания операции, соответствующей вершине из второй группы, с координатами &amp;lt;math&amp;gt;(i, j - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
* &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из первой группы, с координатами &amp;lt;math&amp;gt;(i, j + 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции:&lt;br /&gt;
* при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;промежуточным данным&#039;&#039; алгоритма;&lt;br /&gt;
* при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф можно посмотреть на рис.1. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
[[file:Bliznalg.png|thumb|center|1000px|Рисунок 1. Граф алгоритма умножения разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для умножения разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, размерности &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt; на заполненный вектор &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt; в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* Не более чем &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; сложений и умножений (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вычислений в каждом из ярусов)&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ его сложность будет &amp;lt;math&amp;gt;O(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;n \times m&amp;lt;/math&amp;gt;, хранимая в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; посредством массивов &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Заполненный вектор-столбец &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;2l+m+n+1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; - количество ненулевых элементов в матрице &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: заполненный вектор-столбец &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;i = 1,...,n&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;.&lt;br /&gt;
&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – &#039;&#039;константа&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; - количество ненулевых элементов матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;. Пусть &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; - объем памяти, используемый для хранения значения элемента матрицы, &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; - объём памяти, используемый для хранения номера столбца или строки. В таком случае для хранения матрицы в стандартном представлении нам потребуется объем памяти, равный &amp;lt;math&amp;gt;x \cdot n \cdot m&amp;lt;/math&amp;gt;, для хранения в формате &#039;&#039;&#039;RR(C)&#039;&#039;&#039; - &amp;lt;math&amp;gt;y(n + 1) + (x + y)l&amp;lt;/math&amp;gt;. Таким образом хранение в формате &#039;&#039;&#039;RR(C)&#039;&#039;&#039; не является эффективным (в вопросе используемой памяти) для матриц, в которых &amp;lt;math&amp;gt;l &amp;gt; \frac{xnm - y(n+1)}{x+y}&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;
# Каждый процессор считывает входные данные из файла, зависящего от его номера. Данные имеют вид: вектор &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; и набор определённых строк матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в формате &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; в зависимости от номера процессора и их числа;&lt;br /&gt;
# Процессоры проводят вычисления значений вектора &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; в зависимости от имеющихся данных;&lt;br /&gt;
# Все процессоры отправляют результаты вычисления процессору, выбранному главным, и главный процессор выводит результат вычислений.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot; style=&amp;quot;width:100%&amp;quot;&amp;gt;&lt;br /&gt;
Текст использованной в экспериментах реализации (язык &#039;&#039;С++&#039;&#039;):&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;sstream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;iterator&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef std::shared_ptr&amp;lt;std::vector&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt; &amp;gt; MyData;&lt;br /&gt;
&lt;br /&gt;
MyData ReadData(const std::string&amp;amp; data_path) {&lt;br /&gt;
  std::ifstream file_stream;&lt;br /&gt;
  MyData retval(new std::vector&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;());&lt;br /&gt;
  file_stream.open(data_path);&lt;br /&gt;
&lt;br /&gt;
  while (!file_stream.eof()) {&lt;br /&gt;
    std::string str;&lt;br /&gt;
    std::getline(file_stream, str);&lt;br /&gt;
&lt;br /&gt;
    std::istringstream iss(str);&lt;br /&gt;
    auto temp_1 = (std::istream_iterator&amp;lt;std::string&amp;gt;(iss));&lt;br /&gt;
    auto temp_2 =  (std::istream_iterator&amp;lt;std::string&amp;gt;());&lt;br /&gt;
&lt;br /&gt;
    std::vector&amp;lt;std::string&amp;gt; coordinates{ temp_1, temp_2};&lt;br /&gt;
retval-&amp;gt;push_back(std::vector&amp;lt;int&amp;gt;());&lt;br /&gt;
    for (auto&amp;amp; e : coordinates) {&lt;br /&gt;
      retval-&amp;gt;back().push_back(std::stoi(e));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return retval;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// input: vector b, vector ia, vector ja, vector an&lt;br /&gt;
int main(int argc, char** argv){&lt;br /&gt;
	MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
	int pid, np;&lt;br /&gt;
	MPI_Status *s = new MPI_Status;&lt;br /&gt;
	MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;pid);&lt;br /&gt;
	MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;np);&lt;br /&gt;
	if (argc == 2){&lt;br /&gt;
		int n;&lt;br /&gt;
		int indx = 0;&lt;br /&gt;
		int stp;&lt;br /&gt;
                double strttime = MPI_Wtime();&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; b;&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; ia;&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; ja;&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; an;&lt;br /&gt;
                auto data = ReadData(&amp;quot;data_&amp;quot; + std::to_string(static_cast&amp;lt;long long&amp;gt;(pid)) + &amp;quot;.txt&amp;quot;);&lt;br /&gt;
	        b = (*data)[0];&lt;br /&gt;
		ia = (*data)[1];&lt;br /&gt;
		ja = (*data)[2];&lt;br /&gt;
		an = (*data)[3];&lt;br /&gt;
		n = (*data)[0].size();&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; c; &lt;br /&gt;
                stp = n / np + ((n % np &amp;gt; pid) ? 1 : 0);&lt;br /&gt;
		if (pid == 0){&lt;br /&gt;
			c.resize(n, 0);&lt;br /&gt;
		}&lt;br /&gt;
		else{&lt;br /&gt;
			c.resize(stp, 0);&lt;br /&gt;
		}&lt;br /&gt;
		for (int i = 0; i &amp;lt; stp; i++){&lt;br /&gt;
			int strt = ia[i] - ia[0];&lt;br /&gt;
                        int lstr = ia[i + 1] - ia[i];&lt;br /&gt;
			for (int j = 0; j &amp;lt; lstr; j++){&lt;br /&gt;
				c[i] += an[strt + j] * b[ja[strt + j]];&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		if (pid == 0){&lt;br /&gt;
			for (int i = 1; i &amp;lt; np; i++){&lt;br /&gt;
				indx += n / np + ((n % np &amp;gt; i - 1) ? 1 : 0);&lt;br /&gt;
				stp = n / np + ((n % np &amp;gt; i) ? 1 : 0);&lt;br /&gt;
				MPI_Recv(&amp;amp;c[indx], stp, MPI_INT, i, 0, MPI_COMM_WORLD, s);&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		else{&lt;br /&gt;
			MPI_Send(&amp;amp;c[0], stp, MPI_INT, 0, 0, MPI_COMM_WORLD);&lt;br /&gt;
		}&lt;br /&gt;
		if (pid == 0){&lt;br /&gt;
			for (int e : c) {&lt;br /&gt;
                std::cout &amp;lt;&amp;lt; e &amp;lt;&amp;lt; &amp;quot;\n&amp;quot;;&lt;br /&gt;
                        }&lt;br /&gt;
                        double endtime = MPI_Wtime();&lt;br /&gt;
                        std::cout &amp;lt;&amp;lt; &amp;quot;Success! Time = &amp;quot; &amp;lt;&amp;lt; endtime - strttime &amp;lt;&amp;lt; &amp;quot;\n&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	MPI_Finalize();&lt;br /&gt;
	return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot; style=&amp;quot;width:100%&amp;quot;&amp;gt;&lt;br /&gt;
Для формирования входных данных использовался следующий алгоритм (язык &#039;&#039;Python&#039;&#039;):&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from scipy import sparse as sp&lt;br /&gt;
from numpy.random import randint&lt;br /&gt;
from os import mkdir&lt;br /&gt;
from os.path import join as jn&lt;br /&gt;
&lt;br /&gt;
n = 10000&lt;br /&gt;
np = [1, 2, 4, 8, 16, 32, 64, 128]&lt;br /&gt;
&lt;br /&gt;
a = sp.csr_matrix(randint(0, 2, (n, n)))&lt;br /&gt;
b = randint(1, 5, n)&lt;br /&gt;
i = 0&lt;br /&gt;
&lt;br /&gt;
for j in np:&lt;br /&gt;
  mkdir(&#039;data_&#039; + str(j))&lt;br /&gt;
  indx = 0&lt;br /&gt;
  for i in range(0, j):&lt;br /&gt;
    stp = n / j + (1 if (n % j &amp;gt; i) else 0)&lt;br /&gt;
    ael = a.indptr[indx + stp] - a.indptr[indx]&lt;br /&gt;
    strt = a.indptr[indx]&lt;br /&gt;
    with open(jn(&#039;data_&#039; + str(j), &#039;data_&#039; + str(i) + &#039;.txt&#039;), &#039;w&#039;) as fout:&lt;br /&gt;
    &lt;br /&gt;
      for e in b:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
	&lt;br /&gt;
      s = a.indptr[indx:indx + stp + 1]&lt;br /&gt;
      for e in s:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
	&lt;br /&gt;
      s = a.indices[strt:strt + ael]&lt;br /&gt;
      for e in s:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
    &lt;br /&gt;
      s = a.data[strt:strt + ael]&lt;br /&gt;
      for e in s:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
  &lt;br /&gt;
    indx = indx + n / j + (1 if (n % j &amp;gt; i) else 0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма умножения разреженной матрицы на вектор. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Входные данные формировались на персональном компьютере в силу того, что интерпретатор на суперкомпьютере &amp;quot;Ломоносов&amp;quot; не удовлетворял нужным требованиям, и потом отправлялись на суперкомпьютер для последующей обработки.&lt;br /&gt;
&lt;br /&gt;
Программа была собрана на узле компиляции суперкомпьютера &amp;quot;Ломоносов&amp;quot;, с помощью компилятора &#039;&#039;intel/15.0.090&#039;&#039; и компилятора &#039;&#039;openmpi/1.6.5-icc&#039;&#039;, на языке &#039;&#039;С++11&#039;&#039;.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot; style=&amp;quot;width:100%&amp;quot;&amp;gt;&lt;br /&gt;
Сборка производилась с помощью &#039;&#039;CMakeLists.txt&#039;&#039;, его содержание прилагается:&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 2.8)&lt;br /&gt;
&lt;br /&gt;
project(task1)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_STANDARD 11)&lt;br /&gt;
&lt;br /&gt;
set(CXX_STANDARD_REQUIRED)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_C_COMPILER mpicc)&lt;br /&gt;
set(CMAKE_CXX_COMPILER mpicxx)&lt;br /&gt;
&lt;br /&gt;
find_package(MPI REQUIRED)&lt;br /&gt;
&lt;br /&gt;
include_directories(${MPI_INCLUDE_PATH})&lt;br /&gt;
&lt;br /&gt;
SET(CMAKE_CXX_COMPILER mpicc)&lt;br /&gt;
&lt;br /&gt;
if(MPI_COMPILE_FLAGS)&lt;br /&gt;
  set_target_properties(task1 PROPERTIES&lt;br /&gt;
    COMPILE_FLAGS &amp;quot;${MPI_COMPILE_FLAGS}&amp;quot;)&lt;br /&gt;
endif()&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_FLAGS &amp;quot;-std=c++11 -fpermissive &amp;quot; ${MPI_COMPILE_FLAGS})&lt;br /&gt;
&lt;br /&gt;
set(SOURCE_EXE task1.cpp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
add_executable(task1 ${SOURCE_EXE})&lt;br /&gt;
&lt;br /&gt;
target_link_libraries(task1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запуск производился на вычислительных узлах суперкомпьютера &amp;quot;Ломоносов&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров [1 : 128] по степеням 2;&lt;br /&gt;
* размер матрицы [1000 : 10000] с шагом 1000.&lt;br /&gt;
&lt;br /&gt;
Распределение ненулевых и нулевых коэффициентов: 1:1. Однако стоит обратить внимание, что матрица генерировалась случайным образом, а значит, это лишь распределение, а не точное значение.&lt;br /&gt;
&lt;br /&gt;
[[file:Blizntime.png|thumb|center|1000px|Рисунок 2. Время работы программы в зависимости от количества процессоров и размера матрицы]]&lt;br /&gt;
&lt;br /&gt;
Можно заметить, что при небольшом количестве входных данных, и большом количестве процессоров эффективность распараллеливания падает до нуля, поскольку время вычисления элементов вектора &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; становится несоизмеримо малым по сравнению с временем, затраченным на пересылку в пункте (3). &lt;br /&gt;
&lt;br /&gt;
[[file:Efficiency(paral).png|thumb|center|1000px|Рисунок 4. Эффективность распараллеливания в зависимости от количества процессоров и размера матрицы]]&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;
SciPy [https://docs.scipy.org/doc/scipy-0.18.1/reference/index.html],&lt;br /&gt;
&lt;br /&gt;
MatLab [https://www.mathworks.com/help/matlab/math/sparse-matrix-operations.html],&lt;br /&gt;
&lt;br /&gt;
Intel MKL [https://software.intel.com/en-us/articles/intel-math-kernel-library-inspector-executor-sparse-blas-routines].&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Sannikovats&amp;diff=19963</id>
		<title>Обсуждение участницы:Sannikovats</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Sannikovats&amp;diff=19963"/>
		<updated>2016-12-03T02:37:14Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK) В работе нет исследования масштабируемости алгоритма. К содержанию есть несколько замечаний (отмечены моей подписью), помимо необходимости выполнения основных требований к работе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Статья [[Участница:Sannikovats/Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки (1)]] ==&lt;br /&gt;
&lt;br /&gt;
* Не указан вклад обоих авторов&lt;br /&gt;
* Информационный граф выглядит странно&lt;br /&gt;
** Изображённое на рисунке в разделе 1.7 не является информационным графом. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 10:38, 8 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 1.4 требуется привести описание алгоритма на верхнем уровне (на основе макроопераций), а не то, что там сейчас. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:15, 1 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 1.5 кроме кода нужны также текстовые пояснения. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:15, 1 ноября 2016 (MSK)&lt;br /&gt;
* Отсутствуют заголовки пунктов 2.2-2.6, соответственно пункт 2.1 должен иметь нумерацию 2.4, а пункт 2.2 должен иметь нумерацию 2.7. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 10:39, 8 ноября 2016 (MSK)&lt;br /&gt;
* Не заполнен раздел 2.4 описания. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 16:00, 16 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные последовательные методы построения адаптивных подвижных сеток, которые позволяют значительно повысить точность вычисления определенного интеграла за счет учета характера изменения подынтегральной функции.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Что подразумевается под «подвижностью сеток» для данного алгоритма?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1.1 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Но при распараллеливании этого алгоритма (т.е. при запуске попарно подпрограмм, обрабатывающих половинки разбиваемого интервала) можно столкнуться со следующей проблемой: в реальной системе число процессоров ограничено и время, необходимое для порождения параллельных процессов существенно не равно нулю.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это утверждение сильно зависит от того, как реализована рекурсия. Можно столкнуться с такой проблемой, а можно и не столкнуться.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Основная сложность построения параллельного алгоритма на основе рассмотренного последовательного алгоритма, кроется в том, что, хотя несколько ветвей программы могли бы одновременно обрабатывать разные части интервала интегрирования, координаты концов этих отрезков хранятся в программном стеке процесса и фактически недоступны программисту.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно пояснить, что за программный стек, который недоступен программисту? В чем заключается проблема, если эти данные доступны только одному процессу.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1.2 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Стек выбран исключительно из соображений простоты реализации. Времена выполнения рассмотренных алгоритмов отличаются примерно на 5% в пользу локального стека, таким образом, алгоритм &amp;quot;локального стека&amp;quot; будем считать наилучшим из имеющихся в нашем распоряжении последовательных методов и на его примере построим дальнейшее описание.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Каких алгоритмов и где они рассмотрены? За счет чего образуется выигрыш в 5%? Чем, с точки зрения простоты реализации, стек лучше, по сравнению с очередью?&lt;br /&gt;
&lt;br /&gt;
Все, что написано в разделах 1.1.1 и 1.1.2 сводится к тому, что для реализации рекурсии можно использовать стек. А такую реализацию рекурсии можно (относительно просто) адаптировать под параллельную архитектуру. Разделы написаны крайне путанно, поэтому хорошо бы их переписать.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;math&amp;gt; |sAB - sACB|\leq \epsilon * |sACB| &amp;lt;/math&amp;gt;, что обеспечивает проверку условия устойчивости.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Не отличается ли здесь условие на деление отрезка от того, что приведено в пункте 1.2?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.5 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;//проверка выполнения условия на порядок точности:&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;if(abs(sAB - sACB) &amp;gt;= eps*abs(sACB)) {&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
См. замечание к пункту 1.4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.6 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
В качестве примера нужно привести хотя бы оценки, определяя некоторое разбиение (по возможности в наиболее общем виде) без учета функции. &lt;br /&gt;
&lt;br /&gt;
== Пункт 1.8 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
См. п. 1.6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.9 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Как задается функция или возможность расчета ее значений в алгоритме и реализации?&lt;br /&gt;
Нужно привести размер входных и выходных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.10 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Рассмотренный алгоритм обладает свойством детерминированности, поскольку при определенных входных данных мы будем получать одинаковый результат.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Влияют ли на свойство детерминированности алгоритма выполнение свойства ассоциативности для операции сложения, а также свойства входной функции?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Кроме того, алгоритм обладает внутренним параллелизмом, так как является численно устойчивым как в последовательной, так и в параллельной версиях.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как из численной устойчивости следует «обладание внутренним параллелизмом»?&lt;br /&gt;
Является ли алгоритм устойчивым для любой входной функции?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 2.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нет исследования масштабируемости.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 2.7 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:37, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В настоящее время проблемой вычисления определенного графа на адаптивной сетке по нашим сведениям занимались только М.В. Якобовский и Е.Ю. Кулькова, рассматривавшие в своей работе &amp;quot;РЕШЕНИЕ ЗАДАЧ НА МНОГОПРОЦЕССОРНЫХ ВЫЧИСЛИТЕЛЬНЫХ СИСТЕМАХ С РАЗДЕЛЯЕМОЙ ПАМЯТЬЮ&amp;quot; методы локального и глобального стеков.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Наверное, определенного интеграла на адаптивной сетке?&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Greno4ka&amp;diff=19962</id>
		<title>Обсуждение участника:Greno4ka</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Greno4ka&amp;diff=19962"/>
		<updated>2016-12-03T02:22:12Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK) Работа не готова. Нет разделов 1.3, 1.4, 1.6-1.8, 1.10, 2.4; нет описания параллельного алгоритма и исследования масштабируемости. Есть несколько замечаний (ниже с моей подписью) к тому, что уже написано, помимо выполнения основных требований к работе &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Статья [[Участник:Greno4ka/Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки]] ==&lt;br /&gt;
&lt;br /&gt;
* Нет краткой сводки свойств алгоритма в начале страницы&lt;br /&gt;
* В разделе 1.1 по сути нет описания алгоритма&lt;br /&gt;
* Разделы 1.6-1.8 пусты&lt;br /&gt;
* В разделах 1.3 и 1.4 хотелось бы видеть понятное словесное описание&lt;br /&gt;
* Содержимое раздела 1.4 должно быть внесено в раздел 1.5&lt;br /&gt;
* Не указан вклад каждого автора&lt;br /&gt;
* Не заполнен раздел 2.4 описания. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:59, 16 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.2 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;в некоторых точках значение функции будет вычисляться несколько раз&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В каких точках в формуле для приближенного вычисления интеграла функция вычисляется несколько раз? В чем проблема сохранять рассчитанные значения функции и использовать их далее без перерасчета?&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.3 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
В этом разделе нужно явно описать вычислительное ядро алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Вместо макроструктуры алгоритма здесь приведена реализация структуры данных для стека.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.5 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if (|sAB - sACB| ≥ ε|sACB|) {&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Не отличается ли здесь условие на деление отрезка от того, что приведено в пункте 1.2?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.9 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Как задается входная функция в алгоритме и реализации?&lt;br /&gt;
Нужно указать размер входных-выходных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.10 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Есть ли у алгоритма другие свойства, помимо того, что он адаптируется под заданную функцию?&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Greno4ka&amp;diff=19961</id>
		<title>Обсуждение участника:Greno4ka</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Greno4ka&amp;diff=19961"/>
		<updated>2016-12-03T02:20:35Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK) Работа не готова. Нет разделов 1.3, 1.4, 1.6-1.8, 1.10, 2.4; нет описания параллельного алгоритма и исследования масштабируемости. Есть несколько замечаний (ниже с моей подписью) к тому, что уже написано, помимо выполнения основных требований к работе &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Статья [[Участник:Greno4ka/Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки]] ==&lt;br /&gt;
&lt;br /&gt;
* Нет краткой сводки свойств алгоритма в начале страницы&lt;br /&gt;
* В разделе 1.1 по сути нет описания алгоритма&lt;br /&gt;
* Разделы 1.6-1.8 пусты&lt;br /&gt;
* В разделах 1.3 и 1.4 хотелось бы видеть понятное словесное описание&lt;br /&gt;
* Содержимое раздела 1.4 должно быть внесено в раздел 1.5&lt;br /&gt;
* Не указан вклад каждого автора&lt;br /&gt;
* Не заполнен раздел 2.4 описания. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:59, 16 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.2 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;в некоторых точках значение функции будет вычисляться несколько раз&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В каких точках в формуле для приближенного вычисления интеграла функция вычисляется несколько раз? В чем проблема сохранять рассчитанные значения функции и использовать их далее без перерасчета?&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.3 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
В этом разделе нужно явно описать вычислительное ядро алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Вместо макроструктуры алгоритма здесь приведена реализация структуры данных для стека.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.5 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
if (|sAB - sACB| ≥ ε|sACB|) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Не отличается ли здесь условие на деление отрезка от того, что приведено в пункте 1.2?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.9 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Как задается входная функция в алгоритме и реализации?&lt;br /&gt;
Нужно указать размер входных-выходных данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.10 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:18, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Есть ли у алгоритма другие свойства, помимо того, что он адаптируется под заданную функцию?&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%91%D0%BE%D0%B1%D1%86%D0%BE%D0%B2_%D0%91%D0%BE%D1%80%D0%B8%D1%81/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D0%BB%D0%B0_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%BE_%D1%81%D0%B3%D1%83%D1%89%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%D1%81%D1%8F_%D1%81%D0%B5%D1%82%D0%BA%D0%B8&amp;diff=19960</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%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%91%D0%BE%D0%B1%D1%86%D0%BE%D0%B2_%D0%91%D0%BE%D1%80%D0%B8%D1%81/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D0%BB%D0%B0_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%BE_%D1%81%D0%B3%D1%83%D1%89%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%D1%81%D1%8F_%D1%81%D0%B5%D1%82%D0%BA%D0%B8&amp;diff=19960"/>
		<updated>2016-12-03T02:08:05Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt; O\left( n \right) &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - количество подотрезков, на которые разбился исходный отрезок&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; функция &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; переменной, &amp;lt;math&amp;gt;3&amp;lt;/math&amp;gt; числа (границы отрезка интегрирования, точность))&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; число)&lt;br /&gt;
}}&lt;br /&gt;
Автор статьи: [[Участник:Stalles|Бобцов Борис]] (группа 619)&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;I = \int_a^b{f(x)dx}&amp;lt;/math&amp;gt; от непрерывной функции &amp;lt;math&amp;gt;f(x)&amp;lt;/math&amp;gt;. Если может быть найдена первообразная &amp;lt;math&amp;gt;F(x)&amp;lt;/math&amp;gt; подынтегральной функции, то по формуле Ньютона-Лейбница:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\int_a^b{f(x)dx} = F(b) - F(a). &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если же первообразная не может быть найдена, то для вычисления интеграла прибегают к приближённым формулам, точность которых может быть сделана сколь угодно большой.&lt;br /&gt;
&lt;br /&gt;
Приближённые методы вычисления определённого интеграла в большинстве случаев основаны на том, что определённый интеграл численно равен площади криволинейной трапеции, ограниченной кривой &amp;lt;math&amp;gt; y =f(x)&amp;lt;/math&amp;gt;, сегментом &amp;lt;math&amp;gt; \left[ a,b \right] &amp;lt;/math&amp;gt; оси &amp;lt;math&amp;gt;Ox&amp;lt;/math&amp;gt; и вертикальными прямыми &amp;lt;math&amp;gt;x = a&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;x = b&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Идея данных методов заключается в приближении исходной кривой новой, достаточно близкой к старой, кривой. В качестве этой новой кривой подбирают такую, для которой площадь криволинейной трапеции подсчитывается просто. В зависимости от выбора новой кривой мы получим ту или иную приближённую формулу интегрирования.&lt;br /&gt;
&lt;br /&gt;
Разбивая сегмент интегрирования на несколько достаточно малых частей, на каждом из полученных маленьких сегментов мы можем приблизить интегрируемую функцию прямой. Тем самым мы заменим криволинейную трапецию прямолинейной, формула площади которой проста для вычисления.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
==== Метод трапеций ====&lt;br /&gt;
Будем рассматривать проблему вычисления значения определенного интеграла с некоторой заданной точностью &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;I(a,b) = \int_a^b{f(x)dx}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть на отрезке &amp;lt;math&amp;gt; [a,b] &amp;lt;/math&amp;gt; задана равномерная сетка, содержащая &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt; узел:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; x_{i} = a + \frac{(b - a)} {n} i,   i = 0,...,n &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда, согласно методу трапеций, можно численно найти определенный интеграл от функции &amp;lt;math&amp;gt; f (x) &amp;lt;/math&amp;gt; на отрезке &amp;lt;math&amp;gt;[a,b]&amp;lt;/math&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \int_a^b{f(x)dx} = \frac{b - a}{n} \left( \frac{f(x_0)}{2} + \sum^{n-1}_{i=1} {f(x_i)}  + \frac{f(x_n)}{2} \right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Будем полагать значение &amp;lt;math&amp;gt; I &amp;lt;/math&amp;gt; найденным с точностью &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;, если выполнено условие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; |I_{n_1} - I_{n_2}| \leq \epsilon |I_{n_2}|, n_1 &amp;gt; n_2, &amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;  n_1 &amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt; n_2 &amp;lt;/math&amp;gt; - количество узлов, образующих две разные сетки.&lt;br /&gt;
&lt;br /&gt;
==== Метод рекурсивного деления ====&lt;br /&gt;
&lt;br /&gt;
Метод трапеций обладает следующими недостатками:&lt;br /&gt;
* в некоторых точках значение функции будет вычисляться несколько раз;&lt;br /&gt;
* на всём интервале интегрирования используется равномерная сетка, тогда как число точек, необходимых для достижения заданной точности, зависит от вида функции и может сильно различаться на разных участках сегмента интегрирования.&lt;br /&gt;
&lt;br /&gt;
Метод рекурсивного деления был придуман, чтобы избежать этих недостатков. Суть метода заключается в рекурсивном вызове себя до момента, пока мы не достигнем нужной точности:&lt;br /&gt;
&amp;lt;math&amp;gt; I(a,b) = IntTrap(a, b, f(a), f(b)) = IntTrap(a, (b - a) / 2, f(a), f((b - a) / 2)) + IntTrap((b - a) / 2, b, f((b - a) / 2), f(b)) = ...  &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Однако можно заметить, что координаты концов обрабатываемых отрезков  хранятся в программном стеке процесса &amp;lt;math&amp;gt;IntTrap() &amp;lt;/math&amp;gt;, и недоступны программисту. Это является основной сложностью при построении параллельного алгоритма на основе метода рекурсивного деления.&lt;br /&gt;
&lt;br /&gt;
====Метод локального стека ====&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм использует массив данных, доступ к которым осуществляется по принципу стека - первым удаляется последний из добавленных элементов. Теперь у разных процессов есть возможность обрабатывать отрезки независимо друг от друга. В рассматриваемом алгоритме вместо стека можно было использовать и другие способы хранения заданий, например очередь. Стек выбран исключительно из соображений простоты реализации. Алгоритм локального стека можно считать наилучшим из перечисленных последовательных методов для разработки его параллельной версии.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
В схеме реализации будет явно видно, что алгоритм реализуется при помощи цикла, внутри которого происходит подсчет текущих частичных сумм и проверка достигнутой точности. Сложность данного алгоритма зависит от количества проходов по циклу линейно, поэтому можно считать, что тело этого цикла и является вычислительным ядром данного алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
Как уже было замечено, алгоритм представляет собой три основные части, выполняющиеся в цикле. Сначала вычисляются частичные суммы на имеющемся отрезке, затем проверяется точность вычислений и, в случае, если точность недостаточна, вычисляются новые отрезки.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:123321.png]]&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Будем считать, что описана функция double f( double x ), возвращающая значение f(x) интегрируемой функции f в точке x.&lt;br /&gt;
&lt;br /&gt;
    double f( double x );&lt;br /&gt;
&lt;br /&gt;
    int sp = 0;       //указатель вершины стека&lt;br /&gt;
&lt;br /&gt;
    struct&lt;br /&gt;
    {&lt;br /&gt;
        double a;&lt;br /&gt;
        double b;&lt;br /&gt;
        double fa;&lt;br /&gt;
        double fb;&lt;br /&gt;
        double sab;&lt;br /&gt;
    } stk[1000];      //массив структур, в которых хранятся отложенные значения. 1000 может быть заменена на необходимое число&lt;br /&gt;
&lt;br /&gt;
    //операции доступа к данным стека&lt;br /&gt;
    #define STACK_IS_NOT_FREE ( sp &amp;gt; 0 )&lt;br /&gt;
&lt;br /&gt;
    void PUT_INTO_STACK( double a, double b, double fa, double fb, double sab )&lt;br /&gt;
    {&lt;br /&gt;
        stk[sp].a = a;&lt;br /&gt;
        stk[sp].b = b;&lt;br /&gt;
        stk[sp].fa = fa;&lt;br /&gt;
        stk[sp].fb = fb;&lt;br /&gt;
        stk[sp].sab = sab;&lt;br /&gt;
        ++sp;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void GET_FROM_STACK( double&amp;amp; a, double&amp;amp; b, double&amp;amp; fa, double&amp;amp; fb, double&amp;amp; sab )&lt;br /&gt;
    {&lt;br /&gt;
        --sp;&lt;br /&gt;
        a = stk[sp].a;&lt;br /&gt;
        b = stk[sp].b;&lt;br /&gt;
        fa = stk[sp].fa;&lt;br /&gt;
        fb = stk[sp].fb;&lt;br /&gt;
        sab = stk[sp].sab;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //основная функция &lt;br /&gt;
    int IntTrap(a, b)&lt;br /&gt;
    {&lt;br /&gt;
        double I = 0;        //значение интеграла&lt;br /&gt;
        double fa = f( a );  //значение функции &amp;lt;math&amp;gt;y = f(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&lt;br /&gt;
        double fb = f( b );  //значение функции &amp;lt;math&amp;gt;y = f(x)&amp;lt;/math&amp;gt; в точке &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt;&lt;br /&gt;
        double fc = 0;&lt;br /&gt;
        double c = 0;        //середина отрезка интегрирования&lt;br /&gt;
        double sab = 0;      //&lt;br /&gt;
        double sac = 0;      //&lt;br /&gt;
        double scb = 0;      //&lt;br /&gt;
        double sabc = 0;     //переменные для подсчёта текущих сумм&lt;br /&gt;
        sab = ( fa + fb ) * ( b - a ) / 2;&lt;br /&gt;
        while( 1 )&lt;br /&gt;
        {&lt;br /&gt;
            c = ( a + b ) / 2;&lt;br /&gt;
            fc = f( c );&lt;br /&gt;
            sac = ( fa + fc ) * ( c - a ) / 2;&lt;br /&gt;
            scb = ( fc + fb ) * ( b - c ) / 2;&lt;br /&gt;
            sabc = sac + scb;&lt;br /&gt;
            if( abs( sab - sabc ) &amp;gt; &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; * abs ( sabc ) ) //&amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; - заданная точность&lt;br /&gt;
            {&lt;br /&gt;
                PUT_INTO_STACK( a, c, fa, fc, sac );&lt;br /&gt;
                a = c; &lt;br /&gt;
                fa = fc;&lt;br /&gt;
                sab = scb;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                I += sabc;&lt;br /&gt;
                if( STACK_IS_NOT_FREE )&lt;br /&gt;
                {&lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
                GET_FROM_STACK( a, b, fa, fb, sab );&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return I;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Работа со стеком происходит через операции доступа к данным. В основной функции в цикле происходит вычисление частичных сумм sac и scb, затем проверяется точность if( abs( sab - sacb ) &amp;gt;&amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; * abs ( sacb ) ). В случае достижения необходимой точности частичные суммы добавляются к значению интеграла I, если отрезков не осталось, то программа завершает работу, иначе из стека выгружается следующий отрезок. Если точность не достигнута, то правый полуотрезок загружается в стек, а левый полуотрезок устанавливается как текущий для следующей итерации цикла.&lt;br /&gt;
&lt;br /&gt;
Когда в стеке не останется отрезков, это будет означать, что программа рассчитала все отрезки до точки a включительно, и возвращает значение I как приближённое значение интеграла.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
Пусть для работы алгоритма было необходимо разбить отрезок &amp;lt;math&amp;gt; \left[a, b\right] &amp;lt;/math&amp;gt; на сегменты &amp;lt;math&amp;gt; \left[a=x_0 , x_1\right], \left[a=x_1 , x_2\right],... \left[a=x_{n-1} , x_n = b\right] &amp;lt;/math&amp;gt;.&lt;br /&gt;
Так как каждый раз, когда нам приходится вычислять площадь трапеции на более коротком сегменте, мы делим отрезок пополам, получаем, что длина каждого отрезка равна &amp;lt;math&amp;gt; \left( x_i - x_{i - 1} \right) = \frac{b - a}{2^k} &amp;lt;/math&amp;gt; для некоторого натурального &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Назовём глубиной метода максимальное &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt; из всех &amp;lt;math&amp;gt; k_i : \left( x_i - x_{i - 1} \right) = \frac{b - a}{2^{k_i}} &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Очевидно, что для каждой функции &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; и для каждой точности &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt; глубина алгоритма будет разной. То есть можно считать, что &amp;lt;math&amp;gt; k = k(f(x), \epsilon). &amp;lt;/math&amp;gt; Также понятно, что, если &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;- глубина алгоритма при фиксированных &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;, то максимально возможное количество полученных отрезков, для которых считалась частичная сумма, и количество точек на отрезке &amp;lt;math&amp;gt; \left[a, b\right] &amp;lt;/math&amp;gt; равны соответственно &amp;lt;math&amp;gt; 2^k &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; 2^k + 1 &amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt; k_i = k, i = 1,2,...,n &amp;lt;/math&amp;gt;. В этом худшем с точки зрения количества операций случае алгоритм прокрутит цикл while( 1 ) &amp;lt;math&amp;gt; 1 + 2 + 4 + ... + 2^k = (2^{k + 1}-1) &amp;lt;/math&amp;gt;   раз.&lt;br /&gt;
&lt;br /&gt;
Если не учитывать при расчёте сложности операции работы с памятью, а только сложения/вычитания и умножения*деления, получим, что за каждый выполненный цикл while( 1 ) алгоритм выполняет 7 сложений и 6 умножений. Итого получаем в худшем случае &amp;lt;math&amp;gt; 7*2^k &amp;lt;/math&amp;gt; сложений и &amp;lt;math&amp;gt; 6*2^k &amp;lt;/math&amp;gt; умножений. Кроме этого, алгоритм посчитает значение &amp;lt;math&amp;gt; f(x) &amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt; точках. При этом понятно, что &amp;lt;math&amp;gt; k \leq log(n). &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Получаем, что при разбиении исходного отрезка на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; подотрезков получаем глубину алгоритма &amp;lt;math&amp;gt; k \leq log(n) &amp;lt;/math&amp;gt; и  сложность алгоритма &amp;lt;math&amp;gt; O\left( n + 2^{log n} \right) = O\left( n + n \right) = O\left( n  \right) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При этом из всего вышесказанного сразу видно, что при достаточном количестве вычислительных ресурсов распараллеливания высота ярусно-параллельной формы параллельной программы будет равна глубине &amp;lt;math&amp;gt; k \leq log(n), &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;
[[Файл:Macromy.png|thumb|center|400px|Рис.1. Общая схема алгоритма ]]&lt;br /&gt;
&lt;br /&gt;
На Рис.1 изображена макроструктура алгоритма. На вход алгоритма подаётся функция, границы отрезка интегрирования и нужная точность. В предварительных вычислениях задаются границы первого отрезка и значения функции в них. Далее запускается операция обработки отрезка, в случае недостаточной точности повторяющаяся для двух подотрезков (и так далее, пока не будет достигнута нужная точность), на выход алгоритм выдаёт приближённое значение интеграла на заданном отрезке с необходимой точностью.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим процедуру обработки отрезка подробнее.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:Png граф.png|thumb|center|800px|Рис.2. Информационный граф одной итерации цикла (обработки одного отрезка) ]]&lt;br /&gt;
&lt;br /&gt;
На Рис.2 изображён информационный граф алгоритма обработки отрезка. Синими прямоугольниками изображены входные данные итерации цикла, внутри подписаны имена данных. Кругами изображены операции вычисления переменных, имена которых указаны внутри кругов. Зелёными овалами изображены прочие операции, выполняемые алгоритмом. После операции проверки точности алгоритм загружает правый отрезок в стек, а левый настраивает на дальнейшую обработку, если точность не достигнута, иначе загружает новый отрезок из стека. Затем происходит суммирование текущей частичной суммы с полученными ранее. При отсутствии отрезков в стеке итерация завершается.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Представленный алгоритм обладает хорошим ресурсом параллелизма. В самом деле, пусть в нашем распоряжении есть доступный всем параллельным процессам список отрезков интегрирования, организованный в виде стека. Назовём его глобальным стеком. Предположим, что перед запуском параллельных процессов в глобальный стек помещается единственная запись - координаты концов отрезка интегрирования - в дальнейшем - &amp;quot;отрезок&amp;quot;. Тогда возможно реализовать следующую схему алгоритма, выполняемую каждым из параллельных процессов:&lt;br /&gt;
&lt;br /&gt;
Пока в глобальном стеке есть отрезки:&lt;br /&gt;
*взять один отрезок из глобального стека;&lt;br /&gt;
*выполнить алгоритм локального стека, выполняя при записи в локальный стек следующие операции:&lt;br /&gt;
**если в локальном стеке есть несколько отрезков, а в глобальном стеке отрезки отсутствуют, то&lt;br /&gt;
***переместить часть отрезков из локального стека в глобальный;&lt;br /&gt;
**по исчерпании локального стека добавить полученную частичную сумму к общему значению интеграла.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: &lt;br /&gt;
* функция &amp;lt;math&amp;gt; y = f(x)&amp;lt;/math&amp;gt;;&lt;br /&gt;
* точность &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;;&lt;br /&gt;
* границы отрезка интегрирования &amp;lt;math&amp;gt; a, b.&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Функция может иметь любой вид представления, однако это представление &amp;quot;константно&amp;quot;, то есть можно считать, что объём равен &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt;. Кроме функции, на вход подаётся три вещественных числа, их объём - &amp;lt;math&amp;gt; 3 * sizeof( double ) = O\left( 1 \right) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: &lt;br /&gt;
* число &amp;lt;math&amp;gt;I &amp;lt;/math&amp;gt;, приближённо равное &amp;lt;math&amp;gt; \int_a^b{f(x)dx}&amp;lt;/math&amp;gt; с точностью &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На выход алгоритм выдаёт одно вещественное число, его объём - &amp;lt;math&amp;gt; sizeof( double ) = O\left( 1 \right) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм обладает большой вычислительной мощностью. Кроме того, у него имеется большой потенциал для распараллеливания.&lt;br /&gt;
&lt;br /&gt;
Алгоритм не обладает свойством детерминированности, так как в зависимости от специфических свойств графика входных функций может вести себя для них совершенно по-разному.&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности алгоритма высоко и равно приблизительно &amp;lt;math&amp;gt; \frac{n}{log(n)} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений === &lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Для распараллеливания программы был выбран алгоритм геометрического параллелизма. Весь отрезок интегрирования делился на равные части, количество которых было равно количеству процессов. Далее каждый процесс выполнял функцию &amp;lt;math&amp;gt; IntTrap(a_i, b_i) &amp;lt;/math&amp;gt; для своего отрезка &amp;lt;math&amp;gt; [ a_i, b_i ] &amp;lt;/math&amp;gt; независимо от других процессов. При таком алгоритме мало затрат на обмен данными между процессами, поэтому было решено воспользоваться только средствами библиотеки MPI. При запусках использовалась связка openmpi/1.8.4-gcc + gcc/5.2.0, реализация - тут -&amp;gt; [https://github.com/Stalles/superprak1 ссылка на реализацию.]&lt;br /&gt;
&lt;br /&gt;
Для оценки масштабируемости были произведены запуски на 1, 2, 4, 8, 16, 32, 48, 64, 80, 96, 112 и 128 процессах. В качестве тестируемой функции была выбрана функция &amp;lt;math&amp;gt;1/(x^2) * (sin(1/x))^2&amp;lt;/math&amp;gt;. Кроме того, для каждого количества процессов были произведены запуски при разной точности вычисления интеграла, от &amp;lt;math&amp;gt;10^{-5} &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;10^{-7} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На графиках, представленных ниже, отображена [[Глоссарий#Производительность|производительность]]  и [[Глоссарий#Эффективность распараллеливания|эффективность распараллеливания]] данного алгоритма в зависимости от изменяемых параметров запуска - точности вычислений и числа процессоров.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Png_mapoftime.png|thumb|center|800px|Рис.3. Время работы алгоритма в зависимости от числа процессов и точности вычислений ]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:Myefficiency.png|thumb|center|800px|Рис.4. Эффективность алгоритма в зависимости от числа процессоров и точности вычислений ]]&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов. Кроме того, видно, что при более,чем 40 процессов эффективность становится крайне низкой.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи (точности вычислений)&#039;&#039;&#039; — при увеличении точности вычислений и при постоянном числе процессов эффективность вычислений остаётся практически неизменяемой, очень медленно снижается. Это объясняется тем, что некоторые отрезки интегрирования имеют большую трудоёмкость из-за негладкости функции. Процессы, которым достались такие отрезки, и определяют время работы всей программы.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
На данный момент реализация алгоритма локального стека была указана только в книге Якобовского М.В., Кульковой Е.Ю. &amp;quot;Решение задач на многопроцессорных вычислительных системах с разделяемой памятью.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
# Шнейдер В. Е. и др. Краткий курс высшей математики. Учеб. пособие для втузов. М., «Высш. школа», 1972. 640 с.&lt;br /&gt;
# Якобовский М.В., Кулькова Е.Ю. Решение задач на многопроцессорных вычислительных системах с разделяемой памятью. - М.: СТАНКИН, 2004. – 30 c.&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Stalles&amp;diff=19959</id>
		<title>Обсуждение участника:Stalles</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Stalles&amp;diff=19959"/>
		<updated>2016-12-03T02:06:42Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:06, 3 декабря 2016 (MSK) Хорошее описание метода и алгоритма. Есть несколько замечаний по содержанию и вопросы по исследованию масштабируемости (ниже с моей подписью)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.2.2 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:06, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Однако можно заметить, что координаты концов обрабатываемых отрезков  хранятся в программном стеке процесса &amp;lt;math&amp;gt;IntTrap() &amp;lt;/math&amp;gt;, и недоступны программисту.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что подразумевается под недоступностью стека для программиста, если далее рассматривается работа с этим стеком? Нужно пояснить это утверждение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.2.3 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:06, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Данный алгоритм использует массив данных, доступ к которым осуществляется по принципу стека - первым удаляется последний из добавленных элементов. Теперь у разных процессов есть возможность обрабатывать отрезки независимо друг от друга.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно описать немного подробнее, как из определения стека появляется возможность обрабатывать отрезки независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм локального стека можно считать наилучшим из перечисленных последовательных методов для разработки его параллельной версии.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Где в работе были перечислены последовательные методы, которые здесь сравниваются? С какой точки зрения локальный стек является наилучшим, по сравнению с ними?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.5 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:06, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if( abs( sab - sabc ) &amp;gt; &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; * abs ( sabc ) ) //&amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt; - заданная точность&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Не отличается ли здесь условие на деление отрезка от того, что приведено в пункте 1.2.1?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.9 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:06, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Функция может иметь любой вид представления, однако это представление &amp;quot;константно&amp;quot;, то есть можно считать, что объём равен &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Объём равен &amp;lt;math&amp;gt; O\left( 1 \right) &amp;lt;/math&amp;gt; - это уже не любой вид представления функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 2.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:06, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Правильно ли я понимаю, что представленные результаты по исследованию масштабируемости относятся к несколько другому алгоритму – рассматривается равномерное разбиение отрезка по MPI процессам, а в рамках каждого рассчитывается алгоритм с адаптивной сеткой? Можно ли по полученным результатам судить о масштабируемости исследуемого алгоритма? Нужно это пояснить в работе.&lt;br /&gt;
&lt;br /&gt;
Есть ли в реализации глобальный стек, который описан в работе?  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Статья [[Участник:Бобцов Борис/Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки]] ==&lt;br /&gt;
&lt;br /&gt;
=== Замечания по тексту ===&lt;br /&gt;
* В разделе 1.4 требуется привести описание алгоритма на верхнем уровне (на основе макроопераций), а не то, что там сейчас. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:25, 1 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 1.5 кроме кода нужны также текстовые пояснения. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:25, 1 ноября 2016 (MSK)&lt;br /&gt;
* Граф, приведённый в разделе 1.7 не является информационным графом (ациклический граф, вершины - операции, дуги - информационные зависимости). [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:25, 1 ноября 2016 (MSK)&lt;br /&gt;
** Граф на рис.1 не является графом алгоритма, как написано в подписи к нему. Граф на рис.2 также является каким-то гибридом информационного графа и графа управления - в частности, содержит ветвления, которых в информационном графе быть не должно. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:57, 14 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 1.9 должны быть оценки объёмов входных и выходных данных. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:00, 14 ноября 2016 (MSK)&lt;br /&gt;
* В части 2 должны быть все разделы 2.1-2.7 (некоторые могут быть пустыми). [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:00, 14 ноября 2016 (MSK)&lt;br /&gt;
* Не заполнен раздел 2.4 описания. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 16:04, 16 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 2.4 не приведены все параметры запуска теста - какой компилятор, с какими опциями использовался, какие версии библиотек, на каких узлах проводился запуск и т.д. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:31, 21 ноября 2016 (MSK) &lt;br /&gt;
** Замечание не исправлено. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:21, 28 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 2.4 не приведена использованная в экспериментах реализация алгоритма. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:31, 21 ноября 2016 (MSK) &lt;br /&gt;
** Замечание не исправлено. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:21, 28 ноября 2016 (MSK)&lt;br /&gt;
* Из графиков в разделе 2.4 следует сделать выводы о масштабируемости реализации. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:31, 21 ноября 2016 (MSK)&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Joinmek/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D0%BB%D0%B0_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%BE_%D1%81%D0%B3%D1%83%D1%89%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%D1%81%D1%8F_%D1%81%D0%B5%D1%82%D0%BA%D0%B8&amp;diff=19958</id>
		<title>Участник:Joinmek/Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Joinmek/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D0%BB%D0%B0_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%BE_%D1%81%D0%B3%D1%83%D1%89%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%D1%81%D1%8F_%D1%81%D0%B5%D1%82%D0%BA%D0%B8&amp;diff=19958"/>
		<updated>2016-12-03T01:52:58Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Joinmek|Можарова В. А.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Основная идея большинства методов численного интегрирования состоит в замене подынтегральной функции на более простую, интеграл от которой легко вычисляется аналитически. При замене подынтегральной функции на полином нулевой, первой и второй степени получаются соответственно методы прямоугольников, трапеций и парабол (Симпсона).  &lt;br /&gt;
&lt;br /&gt;
[[Файл:vm_trap.png|300px|center|thumb|Рис.1. Метод трапеций]]&lt;br /&gt;
&lt;br /&gt;
Чтобы посчитать определенный интеграл, участок интегрирования делится на отрезки, на которых подсчитывается значение новой (упрощенной) функции, после чего значения суммируются на всех отрезках. Но чтобы посчитать интеграл с определенной точностью, мы не можем заранее узнать, какие размеры отрезков, нужно использовать, т. к. это зависит от самой функции. Для этого используют адаптивное разбиение участка интегрирования: размер конкретного отрезка определяется во время подсчета значения функции на нем самом. Если заданная точность не была достигнута на данном отрезке, он рекурсивно разбивается на несколько новых и функция подсчитывается уже на них. Таким образом, выигрыш от применения рассмотренного алгоритма рекурсивного разбиения  достигается за счет возможности использования сеток с разным числом узлов на разных участках интервала интегрирования.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Пусть у нас есть интеграл, который надо вычислить с точностью ε:&lt;br /&gt;
&lt;br /&gt;
[[Файл:vm_integral.png|200px|center]]&lt;br /&gt;
&lt;br /&gt;
Предположим, что в результате адаптации сетки для данной функции, на отрезке [A, B] получилась сетка, содержащая n + 1 узел. Тогда согласно методу трапеций, можно численно найти определенный интеграл от функции f(x) на отрезке [A, B]:&lt;br /&gt;
&lt;br /&gt;
[[Файл:vm_common.png|400px|center]]&lt;br /&gt;
&lt;br /&gt;
Будем полагать значение J найденным с точностью ε, если выполнено условие:&lt;br /&gt;
&lt;br /&gt;
[[Файл:vm_condition.png|300px|center]]&lt;br /&gt;
&lt;br /&gt;
где n&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; и  n&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; - количество узлов, образующих две разные сетки.&lt;br /&gt;
Пользуясь формулой&lt;br /&gt;
&lt;br /&gt;
[[Файл:vm_div.png|400px|center]]&lt;br /&gt;
&lt;br /&gt;
рекурсивно делим отрезки интегрирования до достижения на них заданной точности.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Основное время работы алгоритма приходится на вычисление площадей на отрезках, получившихся в результате рекурсивного разбиения:&lt;br /&gt;
&lt;br /&gt;
[[Файл:vm_sq.png|400px|center]]&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;
2. Текущий отрезок делится пополам, и на получившихся отрезках высчитываются новые интегралы&lt;br /&gt;
&lt;br /&gt;
3. Если достигнута заданная точность, то&lt;br /&gt;
&lt;br /&gt;
3.1 Добавить значение интеграла текущего отрезка к общему интегралу&lt;br /&gt;
&lt;br /&gt;
3.2 Если стек пуст, то завершить алгоритм&lt;br /&gt;
&lt;br /&gt;
3.3 Достать из стека отрезок и присвоить его значение текущему отрезку.&lt;br /&gt;
&lt;br /&gt;
4. Иначе &lt;br /&gt;
&lt;br /&gt;
4.1 Один из получившихся маленьких отрезков положить в стек&lt;br /&gt;
&lt;br /&gt;
4.2 Текущему отрезку присвоить значение второго маленького отрезка&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для хранения отрезков интегрирования в данном алгоритме понадобится стек &amp;lt;ref&amp;gt;Якобовский М. В., Кулькова Е. Ю. Решение задач на многопроцессорных вычислительных системах с разделяемой памятью. Москва, 2004.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
    sp=0  //    указатель вершины стека&lt;br /&gt;
    struct {&lt;br /&gt;
          A, B, fA, fB, s&lt;br /&gt;
    } stk[1000] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У стека определен следующий набор операций:&lt;br /&gt;
&lt;br /&gt;
1.	PUT_INTO_STACK - положить элемент в стек&lt;br /&gt;
&lt;br /&gt;
    #define PUT_INTO_STACK(A, B, fA, fB, s)&lt;br /&gt;
    {&lt;br /&gt;
        stk[sp].A=A&lt;br /&gt;
        stk[sp].B=B&lt;br /&gt;
        stk[sp].fA=fA&lt;br /&gt;
        stk[sp].fB=fB&lt;br /&gt;
        stk[sp].s=s&lt;br /&gt;
        sp++&lt;br /&gt;
    } &lt;br /&gt;
&lt;br /&gt;
2.	GET_FROM_STACK - взять верхний элемент из стека&lt;br /&gt;
    #define GET_FROM_STACK(A, B, fA, fB, s)&lt;br /&gt;
    {&lt;br /&gt;
        sp--&lt;br /&gt;
        A=stk[sp].A&lt;br /&gt;
        B=stk[sp].B&lt;br /&gt;
        fA=stk[sp].fA&lt;br /&gt;
        fB=stk[sp].fB&lt;br /&gt;
        s=stk[sp].s&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
3.	STACK_IS_NOT_FREE - проверить стек на наличие в нем элементов&lt;br /&gt;
    #define STACK_IS_NOT_FREE (sp &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    LocalStack (A, B)&lt;br /&gt;
    {&lt;br /&gt;
        // В переменной J храним ответ&lt;br /&gt;
        J=0&lt;br /&gt;
        // Вычисляем значение функции на границах интегрируемого отрезка&lt;br /&gt;
        fA = f(A)&lt;br /&gt;
        fB = f(B)&lt;br /&gt;
        // Вычисляем площадь с помощью метода трапеций&lt;br /&gt;
        sAB = (fA + fB) * (B - A) / 2&lt;br /&gt;
        while (1)&lt;br /&gt;
        {&lt;br /&gt;
            C = (A + B) / 2  // Находим середину отрезка&lt;br /&gt;
            fc = f(C)  // Вычисляем в середине значение функции&lt;br /&gt;
            // Считаем приближенное значение интеграла на получившихся отрезках&lt;br /&gt;
            sAC = (fA + fC) * (C - A) / 2&lt;br /&gt;
            sCB = (fC + fB ) * (B-C) / 2&lt;br /&gt;
            sACB = sAC + sCB&lt;br /&gt;
            if (|sAB - sACB| ≥ ε|sACB|) {  // Если заданная точность не достигнута&lt;br /&gt;
                PUT_INTO_STACK(A, C, fA, fC, sAC)  // то один из отрезков кладем в стек&lt;br /&gt;
                A = C  // и решаем задачу для оставшегося отрезка&lt;br /&gt;
                fA = fC&lt;br /&gt;
                sAB = sCB&lt;br /&gt;
            } else  // Если заданная точность достигнута&lt;br /&gt;
            {&lt;br /&gt;
                J += sACB  // то к общей сумме добавляем полученное число&lt;br /&gt;
                if (STACK_IS_NOT_FREE)  // если стек пуст, то цикл завершается - ответ получен&lt;br /&gt;
                    break &lt;br /&gt;
                GET_FROM_STACK(A, B, fA, fB, sAB)  // иначе берем из стека новый отрезок&lt;br /&gt;
            } &lt;br /&gt;
        }&lt;br /&gt;
        return J &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;
[[Файл:VM_Graph1.png|700px|center|thumb|Рис.2. Информационный граф для алгоритма глобального стека. Ch - выбор отрезка интегрирования, Sq - вычисление площади на отрезке, Div - деление отрезка пополам, Tol - проверка достижения точности, Wr - запись отрезка в лок./глоб. стек, Sum - суммирование результатов]]&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;
2.	Для каждого узла сетки значение функции высчитывается один раз&lt;br /&gt;
&lt;br /&gt;
3.	В параллельной версии алгоритма не требуется управляющий процесс&lt;br /&gt;
&lt;br /&gt;
4.	Алгоритм является детерминированным&lt;br /&gt;
&lt;br /&gt;
5.	Степень исхода вершины информационного графа равна 1, т. к. результат работы каждого процесса в дальнейшем используется только 1 раз.&lt;br /&gt;
&lt;br /&gt;
6.	В представленном параллельном алгоритме сбалансирована загрузка процессов, т. к. при завершении  своих задач каждый процессор обращается за новыми в глобальный стек&lt;br /&gt;
&lt;br /&gt;
7.	Данный алгоритм является устойчивым&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений === &lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Автором данной статьи была выбрана реализация [https://doc.itc.rwth-aachen.de/display/CCP/Parallelizing+an+Algorithm+for+Adaptive+Integration+with+OpenMP RWTH AACHEN UNIVERSITY] на языке C.&lt;br /&gt;
Данная реализация не является масштабируемой, т. к. она основана на механизме общей памяти, а, значит, на архитектуре Blue Gene, на которой она тестировалась, ограничена одним узлом.&lt;br /&gt;
&lt;br /&gt;
Тогда было принято решение модифицировать данный алгоритм, разделив отрезок интегрирования на равные части, количество которых равно количеству запущенных процессов ([https://bitbucket.org/FilmSearchers/globalstack/src Code]). Каждый из них считает интеграл на своем участке, а затем отправляет результат нулевому процессу, на котором происходит суммирование.&lt;br /&gt;
&lt;br /&gt;
Чтобы протестировать систему была выбрана функция sin(x). Вычисление интеграла запускается с разными значениями точности, чтобы пронаблюдать за изменением времени в зависимости от количества итоговых отрезков. Программа запускалась на [https://ru.wikipedia.org/wiki/Blue_Gene Blue Gene]. Использовался компилятор mpicc версии 4.1.2 с опцией -lm. Внутри программы использовалась стандартная библиотека языка C - math, которая была выбрана для подсчета функции синуса в заданных точках, а также библиотека OpenMPI версии 1.68.&lt;br /&gt;
&lt;br /&gt;
[[Файл:VM_Time1.png|800px|center|thumb|Рис.3. Зависимость времени работы алгоритма от числа процессов и заданной точности]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:VM_Efficiency1.png|800px|center|thumb|Рис.4. Зависимость эффективности алгоритма от числа процессов и заданной точности]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Масштабируемость:&lt;br /&gt;
&lt;br /&gt;
Система запускалась на количестве процессов от 8 до 128, начиная с 16 процессов шаг был равен 16. Точность градировалась от 0.00001 до 0.0001 с величиной шага 0.00001. Максимальная эффективность была достигнута на 8 процессах и равна 0.9389. Минимальная - на 128, ее величина 0.2914.&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;
За границей осуществила реализацию компания  [https://doc.itc.rwth-aachen.de/display/CCP/Parallelizing+an+Algorithm+for+Adaptive+Integration+with+OpenMP RWTH Compute Cluster];  группа исследователей во главе с [http://on-demand.gputechconf.com/gtc/2013/poster/pdf/P0237_KameshArumugam.pdf Kamesh Arumugam];  а также команда Berntsen, J.; Espelid, T. O.; and Genz, A.&amp;lt;ref&amp;gt;Berntsen, J.; Espelid, T. O.; and Genz, A. “An Adaptive Algorithm for the Approximate Calculation of Multiple Integrals.” ACM Transactions on Mathematical Software Vol. 17, No. 4, December 1991, Pages 437-451.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Joinmek&amp;diff=19957</id>
		<title>Обсуждение участника:Joinmek</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Joinmek&amp;diff=19957"/>
		<updated>2016-12-03T01:50:16Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK) К работе есть несколько замечаний по содержанию (ниже с моей подписью)&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Чтобы посчитать определенный интеграл, участок интегрирования делится на отрезки, на которых подсчитывается значение новой (упрощенной) функции, после чего значения суммируются на всех отрезках.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Наверное, на отрезках рассчитываются интегралы от новых функций, а их значения уже суммируются?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.5 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if (|sAB - sACB| ≥ ε|sACB|) {  // Если заданная точность не достигнута&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Не отличается ли здесь условие на деление отрезка от того, что приведено в пункте 1.2?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.6 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
В качестве примера нужно привести хотя бы оценки, определяя разбиение отрезка (глубину, неравномерность и пр.) без учета функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.7 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют реализации, где локальные стеки полностью отсутствуют, а все отрезки хранятся в глобальном стеке.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Хорошо бы пояснить в чем достоинства и недостатки такого подхода, по сравнению с тем, что описывается ранее?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.8 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
См. пункт 1.6&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.10 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3.	В параллельной версии алгоритма не требуется управляющий процесс&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно здесь уточнить, что рассматривается алгоритм с общей памятью. Будет ли нужен управляющий процесс при реализации глобального стека на системах с распределенной памятью?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4.	Алгоритм является детерминированным&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Влияют ли на свойство детерминированности алгоритма выполнение свойства ассоциативности для операции сложения, а также свойства входной функции?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7.	Данный алгоритм является устойчивым&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчив для любой функции?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 2.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:46, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Правильно ли я понимаю, что представленные результаты по исследованию масштабируемости относятся к несколько другому алгоритму – рассматривается равномерное разбиение отрезка по MPI процессам, а в рамках каждого рассчитывается алгоритм с адаптивной сеткой? Можно ли по полученным результатам судить о масштабируемости исследуемого алгоритма? Нужно это пояснить в работе. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Данная реализация не является масштабируемой, т. к. она основана на механизме общей памяти, а, значит, на архитектуре Blue Gene, на которой она тестировалась, ограничена одним узлом.&#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;
== Статья [[Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки (2)]] ==&lt;br /&gt;
&lt;br /&gt;
* Нет краткой сводки свойств алгоритма в начале страницы (Исправлено)&lt;br /&gt;
* Нумерация подразделов не соответствует шаблону (Исправлено)&lt;br /&gt;
* Разделы 1.6 и 1.8 (6 и 8 в оригинальной статье) не заполнены (Исправлено)&lt;br /&gt;
* Картинка в разделе 1.7 (7) не является информационным графом (Исправлено)&lt;br /&gt;
** Если это информационный граф, из него следует, что алгоритм строго последовательный. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:29, 21 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
** Приведённый граф очень мелкий, надписи практически нечитаемы. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:29, 21 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
* Раздел 2.7 отсутствует (Исправлено)&lt;br /&gt;
* Список литературы отсутствует (Исправлено)&lt;br /&gt;
* В разделе 1.4 требуется привести описание алгоритма на верхнем уровне (на основе макроопераций), а не то, что там сейчас. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:19, 1 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
* В разделе 1.5 кроме кода нужны также текстовые пояснения. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 18:19, 1 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
* Не заполнен раздел 2.4 описания. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 16:03, 16 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
* Рисунки в статье не подписаны и не пронумерованы. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:29, 21 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
* В разделе 2.4 не приведены все параметры запуска теста - какой компилятор, с какими опциями использовался, какие версии библиотек, на каких узлах проводился запуск и т.д. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:29, 21 ноября 2016 (MSK) (Исправлено)&lt;br /&gt;
* Из графиков в разделе 2.4 следует сделать выводы о масштабируемости реализации. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 14:29, 21 ноября 2016 (MSK) (Исправлено)&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%9C%D0%B0%D0%BA%D0%B0%D1%80%D0%BE%D0%B2%D0%B0_%D0%90%D0%BB%D1%91%D0%BD%D0%B0&amp;diff=19956</id>
		<title>Обсуждение участника:Макарова Алёна</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%9C%D0%B0%D0%BA%D0%B0%D1%80%D0%BE%D0%B2%D0%B0_%D0%90%D0%BB%D1%91%D0%BD%D0%B0&amp;diff=19956"/>
		<updated>2016-12-03T01:32:54Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK) Хорошее и подробное описание метода GMRES. К сожалению, значительно меньше внимания уделено алгоритмическим особенностям, а исследования масштабируемости в работе нет. Есть несколько замечаний по содержанию, которые отмечены моей подписью.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 14:13, 17 ноября 2016 (MSK) необходимо доработать:&lt;br /&gt;
&lt;br /&gt;
Требования были такие: &lt;br /&gt;
- Реализация: полностью собственная или обращение к библиотечной функции (Intel MKL, PETSc, FFTW, ScaLAPACK). В любом случае, текст исследуемой программы должен быть представлен в отчете. &lt;br /&gt;
- Компьютерная платформа может быть любой (Ломоносов, BlueGene или что-то иное). Описание компьютерной платформы должно быть в отчете. &lt;br /&gt;
- Должен быть представлен график сильной масштабируемости (зависимости производительности от числа процессов; если при этом&lt;br /&gt;
ещё и зависимость от размера задачи - это только в плюс). График должен выглядеть пристойно и понятно, оси и единицы измерения должны быть подписаны. К графику обязательно должны быть словесные пояснения! Требовалось подобрать такие размеры задачи и числа процессоров, чтобы отразить на графике характерные точки, описывающие свойства алгоритма и программы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2.3 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Но об этом не верно говорить в общем. Согласно теореме (Greenbaum, Pták and Strakoš), для каждой монотонной последовательности &amp;lt;math&amp;gt; a_1,..., a_{m-1}, a_m = 0 &amp;lt;/math&amp;gt;, найдётся матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; такая что &amp;lt;math&amp;gt;||r_n|| = a_n&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;r_n&amp;lt;/math&amp;gt; невязка, определенная ранее.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы поставить ссылку на этот результат и указать работу в списке литературы. Чему здесь соответствует индекс &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; – номеру итерации?&lt;br /&gt;
&lt;br /&gt;
Опечатка для границ &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;: &lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\mathcal{K}_i = span \{ e_n, e_{n-1}, ..., e_{n-i+1}\}, i \le i \le n &lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2.3.2 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Опечатка: &#039;&#039;&#039;Если матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; является симметрично ...&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пусть несимметричная матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; имеет симметричный портрет и число ненулевых элементов в нижнем(верхнем) треугольнике равно  &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Зачем здесь нужно требование о симметричном потрете матрицы? Можно ли записать оценки для разреженной матрицы без этого условия?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно привести более подробное описание графа, принятых обозначений и т.п. Рассматривается ли здесь разреженная матрица, для которой приведены оценки сложности последовательного алгоритма в пункте 1.6?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Опечатка: &#039;&#039;&#039;при вычислении невязок матрича ...&#039;&#039;&#039;&lt;br /&gt;
Опечатка: &#039;&#039;&#039;вычисления скалярных проихведений ...&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В разделе рассматриваются 2 «интенсивных в вычислительном плане этапа», а граф в 1.7 строится только для умножения матрицы на вектор. С чем это связано?&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для систем с разряженной матрицей алгоритм требует гораздо меньшей вычислительной мощности.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы привести оценки в работе как для плотной, так и для разреженной матрицы, чтобы проиллюстрировать данное утверждение&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Одной из важных практических особенностей метода является  то, что на первых итерациях метод сходится гораздо быстрее, чем асимптотически. Для ускорения сходимости метода минимальных невязок целесообразно время о времени использовать один шаг двух-шагового метода минимальных невязок.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
То, что целесообразно использовать один шаг двух-шагового метода минимальных невязок нужно описать подробнее. Что здесь понимается под двух-шаговым методом GMRES? Почему выполнение только одного шага дает выигрыш – нужны пояснения и/или ссылки.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.3.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При выполнении параллельного алгоритма решения систем линейных алгебраических уравнений необходимо распределить входные данные наиболее рациональным способом. Матрица коэффициентов разбивается на непрерывные горизонтальные полосы. Распределение вектора правой части и начального приближения выполнено по принципу дублирования, т.е. все элементы векторов скопированы на все процессоры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В чем рациональность такого подхода для тех задач, в которых размерность вектора не помещается в памяти?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Если процессор хранит строку матрицы и одиночные элементы векторов правой части и начального приближения, то общее число сохраняемых элементов имеет порядок  . Если же процессор хранит строку матрицы и все элементы векторов, то общее число сохраняемых элементов также порядка  .&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Величина для &amp;quot;порядка&amp;quot; пропущена.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Таким образом, при дублировании и при разделении векторов требования к объему памяти из одного класса сложности.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это утверждение нужно переформулировать и пояснить. Что здесь понимается под классом сложности?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.3.2 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;нахождение взвешенной суммы векторов&#039;&#039;&#039; – линейной комбинации векторов?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.3.3 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Требуется ли выполнение объединений на каждой итерации метода? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нет исследования масштабируемости&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.7 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:32, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Опечатка: &#039;&#039;&#039;Список пакетов, в которых присутствует реализация методА минимизации обобщенной невязки:&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%90%D0%BD%D1%8E%D1%88%D0%B5%D0%B2%D0%B0_%D0%98%D1%80%D0%B8%D0%BD%D0%B0&amp;diff=19955</id>
		<title>Обсуждение участника:Анюшева Ирина</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%90%D0%BD%D1%8E%D1%88%D0%B5%D0%B2%D0%B0_%D0%98%D1%80%D0%B8%D0%BD%D0%B0&amp;diff=19955"/>
		<updated>2016-12-03T01:10:12Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK) К работе есть несколько замечаний по содержанию (отмечены моей подписью), помимо выполнения требований к работе&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 14:13, 17 ноября 2016 (MSK) необходимо доработать:&lt;br /&gt;
&lt;br /&gt;
Требования были такие: &lt;br /&gt;
- Реализация: полностью собственная или обращение к библиотечной функции (Intel MKL, PETSc, FFTW, ScaLAPACK). В любом случае, текст исследуемой программы должен быть представлен в отчете. &lt;br /&gt;
- Компьютерная платформа может быть любой (Ломоносов, BlueGene или что-то иное). Описание компьютерной платформы должно быть в отчете. &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.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Обобщенный метод минимальных невязок (GMRES) для решения системы линейных алгебраических уравнений аппроксимирует решение с помощью вектора в подпространстве Крылова с минимальным остатком.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь подразумевается по «минимальным остатком»?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Метод по праву считается одним из самых эффективных численных методов решения несимметричных систем.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Чем GMRES эффективнее с вычислительной точки зрения, например, других итерационных Крыловских методов для несимметричных матриц? &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Метод обобщенных минимальных невязок популярен из-за наличия ряда преимуществ: он ошибкоустойчив, допускает эффективное распараллеливание, не требует нахождения параметра релаксации, обладает суперлинейной скоростью сходимости.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно пояснить, что подразумевается под ошибкоустойчивостью метода? Причем здесь параметр релаксации? Обычно вместо «суперлинейной сходимости», пишут сверхлинейная сходимость. Хорошо бы выделить класс методов, с которыми сравнивается GMRES в плане эффективности и преимуществ. Так, например, стабилизированный метод бисопряженных градиентов также «допускает эффективное распараллеливание и не требует нахождения параметра релаксации».&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Зато широкое распространение получила перезапускаемая версия метода, подоразумевающая перезапуск метода каждые m итераций.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Сохраняются ли преимущества метода для версии метода GMRES с рестартами? Например, сверхлинейная сходимость и ошибкоустойчивость? Свойства (достоинства и недостатки) GMRES(m) лучше описать подробнее.&lt;br /&gt;
&lt;br /&gt;
Опечатка - &#039;&#039;&#039;подоразумевающая перезапуск метода каждые m итераций&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно уточнить какая норма здесь рассматривается. Также в нескольких местах (в этом и следующих разделах) при записи нормы пропущена одна правая вертикальная скобка.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выбрать произвольное &amp;lt;math&amp;gt;x_0&amp;lt;/math&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для любого &amp;lt;math&amp;gt;x_0&amp;lt;/math&amp;gt; достигается сходимость?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно дополнить раздел оценками для разреженной матрицы по числу ненулевых элементов. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Хорошо бы подробнее описать структуру алгоритма в блоках ортогонализации и минимизации невязки. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для нахождения матрично-векторных произведений при вычислении невязок матрица СЛАУ должна быть подвергнута декомпозиции на строчные блоки, размеры которых определяются требованиями равномерности загрузки.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Можно ли рассматривать декомпозицию матрицы по «двумерным» блокам, а не только по строкам?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Обработка вектора решения дублируется на всех процессах.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В практических задачах размерность вектора решения может быть очень большой и не помещаться в память процессора. Как предлагается решать такие задачи? Если такие задачи не рассматриваются, то это нужно явно прописать.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Однако, есть примеры, в которых видно, что первые &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; итераций дают невязку, равную некой константе, а на итерации под номером &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; получаем точное решение&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно привести такие примеры и описать подробнее данные случаи или указать ссылку на работу, где такие примеры построены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно описать структуру матрицы, которая рассматривалась в экспериментах. Какое условие на выход из итерационного процесса использовалось в расчетах?&lt;br /&gt;
&lt;br /&gt;
С чем связана такая низкая эффективность реализации?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Из рисунков видно, что при увеличении количества процессов, а также при увеличении размерности задачи, производительность параллельной реализации алгоритма уменьшается, что говорит о плохой масштабируемости.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно объяснить в чем причина плохой масштабируемости алгоритма. Особенно с учетом того, что в разделе 1.1 Вы пишите о том, что метод GMRES «допускает эффективное распараллеливание».&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%90%D0%BD%D1%8E%D1%88%D0%B5%D0%B2%D0%B0_%D0%98%D1%80%D0%B8%D0%BD%D0%B0&amp;diff=19954</id>
		<title>Обсуждение участника:Анюшева Ирина</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%90%D0%BD%D1%8E%D1%88%D0%B5%D0%B2%D0%B0_%D0%98%D1%80%D0%B8%D0%BD%D0%B0&amp;diff=19954"/>
		<updated>2016-12-03T01:06:14Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK) К работе есть несколько замечаний по содержанию (отмечены моей подписью), помимо выполнения требований к работе&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 14:13, 17 ноября 2016 (MSK) необходимо доработать:&lt;br /&gt;
&lt;br /&gt;
Требования были такие: &lt;br /&gt;
- Реализация: полностью собственная или обращение к библиотечной функции (Intel MKL, PETSc, FFTW, ScaLAPACK). В любом случае, текст исследуемой программы должен быть представлен в отчете. &lt;br /&gt;
- Компьютерная платформа может быть любой (Ломоносов, BlueGene или что-то иное). Описание компьютерной платформы должно быть в отчете. &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.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Обобщенный метод минимальных невязок (GMRES) для решения системы линейных алгебраических уравнений аппроксимирует решение с помощью вектора в подпространстве Крылова с минимальным остатком.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь подразумевается по «минимальным остатком»?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Метод по праву считается одним из самых эффективных численных методов решения несимметричных систем.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Чем GMRES эффективнее с вычислительной точки зрения, например, других итерационных Крыловских методов для несимметричных матриц? &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Метод обобщенных минимальных невязок популярен из-за наличия ряда преимуществ: он ошибкоустойчив, допускает эффективное распараллеливание, не требует нахождения параметра релаксации, обладает суперлинейной скоростью сходимости.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно пояснить, что подразумевается под ошибкоустойчивостью метода? Причем здесь параметр релаксации? Обычно вместо «суперлинейной сходимости», пишут сверхлинейная сходимость. Хорошо бы выделить класс методов, с которыми сравнивается GMRES в плане эффективности и преимуществ. Так, например, стабилизированный метод бисопряженных градиентов также «допускает эффективное распараллеливание и не требует нахождения параметра релаксации».&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Зато широкое распространение получила перезапускаемая версия метода, подоразумевающая перезапуск метода каждые m итераций.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Сохраняются ли преимущества метода для версии метода GMRES с рестартами? Например, сверхлинейная сходимость и ошибкоустойчивость? Свойства (достоинства и недостатки) GMRES(m) лучше описать подробнее.&lt;br /&gt;
&lt;br /&gt;
Опечатка - &#039;&#039;&#039;подоразумевающая перезапуск метода каждые m итераций&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно уточнить какая норма здесь рассматривается. Также в нескольких местах (в этом и следующих разделах) при записи нормы пропущена одна правая вертикальная скобка.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выбрать произвольное &amp;lt;math&amp;gt;x_0&amp;lt;/math&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для любого &amp;lt;math&amp;gt;x_0&amp;lt;/math&amp;gt; достигается сходимость?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно дополнить раздел оценками для разреженной матрицы по числу ненулевых элементов. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Хорошо бы подробнее описать структуру алгоритма в блоках ортогонализации и минимизации невязки. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для нахождения матрично-векторных произведений при вычислении невязок матрица СЛАУ должна быть подвергнута декомпозиции на строчные блоки, размеры которых определяются требованиями равномерности загрузки.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Можно ли рассматривать декомпозицию матрицы по «двумерными» блокам, а не только по строкам?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Обработка вектора решения дублируется на всех процессах.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В практических задачах размерность вектора решения может быть очень большой и не помещаться в память процессора. Как предлагается решать такие задачи? Если такие задачи не рассматриваются, то это нужно явно прописать.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Однако, есть примеры, в которых видно, что первые &amp;lt;math&amp;gt;m-1&amp;lt;/math&amp;gt; итераций дают невязку, равную некой константе, а на итерации под номером &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; получаем точное решение&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно привести такие примеры; описать подробнее или указать ссылку на работу, где такие примеры построены.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 04:05, 3 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно описать структуру матрицы, которая рассматривалась в экспериментах. Какое условие на выход из итерационного процесса использовалось в расчетах?&lt;br /&gt;
&lt;br /&gt;
С чем связана такая низкая эффективность реализации?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Из рисунков видно, что при увеличении количества процессов, а также при увеличении размерности задачи, производительность параллельной реализации алгоритма уменьшается, что говорит о плохой масштабируемости.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно объяснить в чем причина плохой масштабируемости алгоритма. Особенно с учетом того, что в разделе 1.1 Вы пишите о том, что метод GMRES «допускает эффективное распараллеливание».&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Alexander34396/%D0%9E%D0%B1%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%BC%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D0%BD%D0%B5%D0%B2%D1%8F%D0%B7%D0%BE%D0%BA&amp;diff=19870</id>
		<title>Участник:Alexander34396/Обобщенный метод минимальных невязок</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Alexander34396/%D0%9E%D0%B1%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D0%BC%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D0%BD%D0%B5%D0%B2%D1%8F%D0%B7%D0%BE%D0%BA&amp;diff=19870"/>
		<updated>2016-12-02T02:47:53Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Основные авторы описания: [[#Участник:Alexander34396|А.А.Ульянов]] (разделы [[#Общее описание алгоритма|1.1]], [[#Математическое описание алгоритма|1.2]], [[#Вычислительное ядро алгоритма|1.3]], [[#Макроструктура алгоритма|1.4]], [[#Схема реализации последовательного алгоритма|1.5]], [[#Последовательная сложность алгоритма|1.6]], [[#Входные и выходные данные алгоритма|1.9]], [[#Существующие реализации алгоритма|2.7]]), [[#Участник:Kpetrov|К.Петров]] (разделы [[#Информационный граф|1.7]], [[#Ресурс параллелизма алгоритма|1.8]], [[#Свойства алгоритма|1.10]], [[#Масштабируемость алгоритма и его реализации|2.4]]).&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Обобщенный метод минимальных невязок&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt; O(nm^2) &amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt; (n + 1)^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;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Обобщённый метод минимальных невязок&#039;&#039;&#039; ({{lang-en|Generalized minimal residual method, GMRES}}) - итерационный метод численного решения системы линейных алгебраических уравнений с невырожденной матрицей. Метод основан на минимизации квадратичного функционала невязки на подпространствах Крылова. Разработан Юсефом Саадом и Мартином Шульцем&amp;lt;ref&amp;gt; Y.Saad, M.H. Schultz, GMRES: A generalized minimal residual algorithm for solving nonsymmetric linear systems, SIAM J. Scientific and Stat. Comp. 7: 856-869 (1986) &amp;lt;/ref&amp;gt; в 1986 году как обобщение метода MINRES&amp;lt;ref&amp;gt;C. C. Paige and M. A. Saunders. Solution of sparse indefinite systems of linear equations, SIAM J. Numerical Analysis 12, 617-629 (1975)&amp;lt;/ref&amp;gt; на случай систем с несимметричными матрицами.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039; &lt;br /&gt;
* система линейных алгебраических уравнений вида &amp;lt;math&amp;gt; Ax = b &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; — невырожденная матрица размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;-на-&amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
* &amp;lt;math&amp;gt; x_0 &amp;lt;/math&amp;gt; - начальное приближение.&lt;br /&gt;
&#039;&#039;&#039;Вычисляемые данные:&#039;&#039;&#039; &lt;br /&gt;
* &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt; - приближённое решение исходной системы.&lt;br /&gt;
&lt;br /&gt;
Метод GMRES приближает точное решение исходной системы &amp;lt;math&amp;gt; Ax = b &amp;lt;/math&amp;gt; вектором &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt;, который минимизирует Евклидову норму невязки &amp;lt;math&amp;gt; r_m = Ax_m - b&amp;lt;/math&amp;gt; на подпространстве Крылова:&lt;br /&gt;
: &amp;lt;math&amp;gt; K_m = K_m(A,b) = \operatorname{span} \, \{ b, Ab, A^2b, \ldots, A^{m-1}b \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \operatorname{span} \, \{ a_1, a_2, \ldots, a_m \} &amp;lt;/math&amp;gt; - линейная оболочка системы векторов &amp;lt;math&amp;gt; \{ a_1, a_2, \ldots, a_m \} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На каждой итерации метода решение уточняется поправкой, представленной в виде разложения по ортонормированному базису пространства &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt;: &lt;br /&gt;
: &amp;lt;math&amp;gt; x_m = x_0 + z_m &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; x_0 &amp;lt;/math&amp;gt; - некоторое начальное приближение, &amp;lt;math&amp;gt; z_m \in K_m &amp;lt;/math&amp;gt; - поправка решения.&lt;br /&gt;
&lt;br /&gt;
=== Ортогонализация Арнольди ===&lt;br /&gt;
&lt;br /&gt;
Для построения ортонормированного базиса &amp;lt;math&amp;gt; v_1, v_2, \ldots, v_m &amp;lt;/math&amp;gt; пространства Крылова &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt; метод использует процесс Арнольди.&lt;br /&gt;
&lt;br /&gt;
Идея процесса Арнольди состоит в том, что для нахождения вектора &amp;lt;math&amp;gt; v_{j+1} &amp;lt;/math&amp;gt; при известных векторах &amp;lt;math&amp;gt; v_1, v_2, \ldots, v_j &amp;lt;/math&amp;gt; необходимо вычислить вектор &amp;lt;math&amp;gt; Av_j &amp;lt;/math&amp;gt; и ортонормировать этот вектор относительно &amp;lt;math&amp;gt; v_1, v_2, \ldots, v_j &amp;lt;/math&amp;gt;:&lt;br /&gt;
: &amp;lt;math&amp;gt; v_{j+1} = \frac{\hat{v}_{j+1}}{\|\hat{v}_{j+1}\|_2} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \hat{v}_{j+1} = Av_j - \sum_{i=1}^j h_{ij}v_{i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Коэффициенты &amp;lt;math&amp;gt; h_{ij} = (Av_j, v_i) &amp;lt;/math&amp;gt; определяются из условия ортогональности:&lt;br /&gt;
: &amp;lt;math&amp;gt; A(v_j, v_k) - \sum_{i=1}^j h_{ij}(v_{i}, v_k)  = 0 &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \quad k=1,\ldots,j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат процедуры Арнольди совпадает с результатом процесса Грамма-Шмидта, применённого к векторам &amp;lt;math&amp;gt; \{b, Ab, A^2b, \ldots, A^{m-1}b\} &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039; &lt;br /&gt;
* &amp;lt;math&amp;gt; v_1 &amp;lt;/math&amp;gt;, такой что &amp;lt;math&amp;gt; \|v_1\|_2 = 1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
* матрица &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размером &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;-на-&amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вычисляемые данные:&#039;&#039;&#039; &lt;br /&gt;
* &amp;lt;math&amp;gt; v_1, v_2, \ldots, v_m &amp;lt;/math&amp;gt; - ортонормированный базис пространства Крылова &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм процесса:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Выполнять для &amp;lt;math&amp;gt; \quad j=1,\ldots,m &amp;lt;/math&amp;gt;:&lt;br /&gt;
# &amp;lt;math&amp;gt; h_{ij} = (Av_j, v_i), \quad i=1,\ldots,j &amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt; \hat{v}_{j+1} = Av_j - \sum_{i=1}^j h_{ij}v_{i} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt; h_{j+1j} = \|\hat{v}_{j+1}\|_2 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt; v_{j+1} = \frac{\hat{v}_{j+1}}{h_{j+1j}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При введении матричных обозначений можно записать:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Поправка решения:&lt;br /&gt;
: &amp;lt;math&amp;gt; z_m = V_my_m &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; y_m \in \mathbb{R}^m &amp;lt;/math&amp;gt; - вектор коэффициентов, &amp;lt;math&amp;gt; V_m = [v_1|v_2|...|v_m] &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Матричное представление процесса Арнольди:&lt;br /&gt;
: &amp;lt;math&amp;gt; AV_m = V_{m+1}H_{m+1m} = V_mH_m + h_{m+1m}v_{m+1} e_m^T &amp;lt;/math&amp;gt;, &lt;br /&gt;
где &lt;br /&gt;
: &amp;lt;math&amp;gt;H_{m+1m} = \begin{bmatrix}h_{11} &amp;amp; h_{12} &amp;amp; h_{13} &amp;amp;... &amp;amp; h_{1m-1} &amp;amp; h_{1m} \\ h_{21} &amp;amp; h_{22} &amp;amp; h_{23} &amp;amp; ... &amp;amp; h_{2m-1} &amp;amp; h_{2m} \\ 0 &amp;amp; h_{32} &amp;amp; h_{33} &amp;amp;...&amp;amp; h_{3m-1} &amp;amp; h_{3m} \\ ... &amp;amp; ... &amp;amp; ... &amp;amp; ... &amp;amp; ... &amp;amp; ... \\ 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; ... &amp;amp; h_{m m-1} &amp;amp; h_{mm} \\0 &amp;amp; 0 &amp;amp; 0 &amp;amp; ... &amp;amp; 0 &amp;amp; h_{m+1 m}\end{bmatrix}&amp;lt;/math&amp;gt;&lt;br /&gt;
- верхняя матрица Хессенберга размерности &amp;lt;math&amp;gt; m+1 &amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Минимизация функционала невязки ===&lt;br /&gt;
&lt;br /&gt;
Невязка исходной системы имеет вид:&lt;br /&gt;
: &amp;lt;math&amp;gt; r_m = b - A(x_0 + z_m) = r_0 - AV_my_m = \beta v_1 - V_{m+1}H_{m+1m}y_m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \beta = \|r_0\|_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
C учетом того, что матрица &amp;lt;math&amp;gt; V_{k+1} &amp;lt;/math&amp;gt; составлена из ортонормированных векторов:&lt;br /&gt;
: &amp;lt;math&amp;gt; r_m = \beta V_{m+1}e_1 - H_{m+1m}y_m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; e_1 = (1,0,0,\ldots,0)^T &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Норма невязки &amp;lt;math&amp;gt; r_m &amp;lt;/math&amp;gt;:&lt;br /&gt;
: &amp;lt;math&amp;gt; \|r_m\|_2 = \|\beta e_1 - H_{m+1m}y_m\|_2 &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Норма &amp;lt;math&amp;gt; \|r_m\|_2 &amp;lt;/math&amp;gt; достигает минимума при &amp;lt;math&amp;gt; \beta e_1 = H_{m+1m}y_m &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для нахождения решения такой системы, матрица &amp;lt;math&amp;gt; H_{m+1m} &amp;lt;/math&amp;gt; приводится к верхнему треугольному виду с помощью &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt; последовательных [[Метод_Гивенса_(вращений)_QR-разложения_квадратной_матрицы_(вещественный_вариант)|вращений Гивенса]].&lt;br /&gt;
&lt;br /&gt;
=== Общая схема метода ===&lt;br /&gt;
&lt;br /&gt;
В общем виде m-aя итерация алгоритма GMRES может быть записан следующим образом:&lt;br /&gt;
&lt;br /&gt;
# найти ортонормированный базис &amp;lt;math&amp;gt; V_m &amp;lt;/math&amp;gt; подпространства &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt; с помощью ортогонализации Арнольди;&lt;br /&gt;
# найти &amp;lt;math&amp;gt; y_m &amp;lt;/math&amp;gt;, минимизирующий &amp;lt;math&amp;gt; \|r_m\|_2 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вычислить &amp;lt;math&amp;gt; x_m = x_0 + V_my_m &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; x_0 &amp;lt;/math&amp;gt; - начальное приближение;&lt;br /&gt;
# вычислить &amp;lt;math&amp;gt; r_m &amp;lt;/math&amp;gt; и остановиться,если требуемая точность была достигнута, иначе повторить.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро последовательной версии метода GMRES состоит из двух частей:&lt;br /&gt;
* Вычисление ортонормированного базиса &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt;;&lt;br /&gt;
* Формирование приближенного решения &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для вычисления ортонормированного базиса &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt; метод использует процесс Арнольди:&lt;br /&gt;
: &amp;lt;math&amp;gt; h_{j+1j}v_{j+1} = Av_j - \sum_{i=1}^j h_{ij}v_{j} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; h_{ij} = (Av_j, v_i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; \quad j=1,\ldots,m &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для нахождения приближённого решения &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt; метод использует формулу:&lt;br /&gt;
: &amp;lt;math&amp;gt; x_m = x_0 + V_my_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;
* Вычисление Евклидовой нормы вектора;&lt;br /&gt;
* Умножение вектора на скаляр;&lt;br /&gt;
* Деление вектора на скаляр.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На практике используется перезапускаемая версия метода - GMRES(m):&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;1 Подготовка перед итерационным процессом:&#039;&#039;&#039;&lt;br /&gt;
:1.1 Выбрать начальное приближение &amp;lt;math&amp;gt; x_0 &amp;lt;/math&amp;gt;;&lt;br /&gt;
:1.2 Посчитать невязку &amp;lt;math&amp;gt; r_0 = b - Ax_0 &amp;lt;/math&amp;gt;;&lt;br /&gt;
:1.3 Вычислить &amp;lt;math&amp;gt; v_1 = \frac{r_0}{\|r_0\|_2} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2 Построение ортонормированного базиса &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt;:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
: Для всех &amp;lt;math&amp;gt; j &amp;lt;/math&amp;gt; от 1 до m по нарастанию выполнять:&lt;br /&gt;
:2.1 &amp;lt;math&amp;gt; h_{ij} := (Av_j, v_i), \quad i=1,\ldots,j &amp;lt;/math&amp;gt;;&lt;br /&gt;
:2.2 &amp;lt;math&amp;gt; \hat{v}_{j+1} := Av_j - \sum_{i=1}^j h_{ij}v_{i} &amp;lt;/math&amp;gt;;&lt;br /&gt;
:2.3 &amp;lt;math&amp;gt; h_{j+1j} = \|\hat{v}_{j+1}\|_2 &amp;lt;/math&amp;gt;;&lt;br /&gt;
:2.4 &amp;lt;math&amp;gt; v_{j+1} = \frac{\hat{v}_{j+1}}{h_{j+1j}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3 Вычисление &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt;:&#039;&#039;&#039;&lt;br /&gt;
:3.1 &amp;lt;math&amp;gt; x_m = x_0 + V_my_m &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;y_m&amp;lt;/math&amp;gt; минимизирует &amp;lt;math&amp;gt;\|r_0 - AV_my_m\|_2&amp;lt;/math&amp;gt;;&lt;br /&gt;
:3.2 Вычислить &amp;lt;math&amp;gt; r_m &amp;lt;/math&amp;gt;;&lt;br /&gt;
:3.3 Если требуемая точность достигнута, остановиться.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4 Перезапуск:&#039;&#039;&#039;&lt;br /&gt;
:4.1 &amp;lt;math&amp;gt;x_0 = x_m&amp;lt;/math&amp;gt;;&lt;br /&gt;
:4.2 &amp;lt;math&amp;gt;v_1 = \frac{r_m}{\|r_m\|_2}&amp;lt;/math&amp;gt;;&lt;br /&gt;
:4.3 Перейти к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Если пренебречь сложностью вычисления &amp;lt;math&amp;gt; y_m &amp;lt;/math&amp;gt;, то общую сложность алгоритма GMRES можно разделить на две части:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Сложность вычисления ортонормированного базиса пространства &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt;:&#039;&#039;&#039;&lt;br /&gt;
:a) Для вычисления &amp;lt;math&amp;gt; j &amp;lt;/math&amp;gt;-го вектора базиса &amp;lt;math&amp;gt; K_m, j &amp;lt; m &amp;lt;/math&amp;gt; требуется:&lt;br /&gt;
:: &amp;lt;math&amp;gt; NZ + (2j + 1)n &amp;lt;/math&amp;gt; мультипликативных операций, где &amp;lt;math&amp;gt; NZ &amp;lt;/math&amp;gt; - количество ненулевых элементов матрицы &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;. &lt;br /&gt;
:b) Вычисление последнего вектора базиса требует:&lt;br /&gt;
:: &amp;lt;math&amp;gt; n(m + 1) &amp;lt;/math&amp;gt; мультипликативных операций. &lt;br /&gt;
:c) Общая мультипликативная сложность вычисления ортонормированного базиса &amp;lt;math&amp;gt; K_m &amp;lt;/math&amp;gt;: &lt;br /&gt;
:: &amp;lt;math&amp;gt; O(nm^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Сложность вычисления приближённого решения &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt;:&#039;&#039;&#039; &lt;br /&gt;
:a) Вычисление этой формулы требует &amp;lt;math&amp;gt; nm &amp;lt;/math&amp;gt; мультипликативных операций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[File: Drawing.png|thumb|center|350px|&#039;&#039;&#039;Рис. 1&#039;&#039;&#039; &lt;br /&gt;
&#039;&#039;&#039;input&#039;&#039;&#039; - входные данные алгоритма (квадратная матрица, вектор правой части, начальное приближение, точность решения);&lt;br /&gt;
 &#039;&#039;&#039;&amp;lt;math&amp;gt; A_i &amp;lt;/math&amp;gt;&#039;&#039;&#039; - шаги алгоритма Арнольди, &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; - нахождение невязки на &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;-ой итерации; &lt;br /&gt;
&#039;&#039;&#039;if&#039;&#039;&#039; - вычисление &amp;lt;math&amp;gt; r_m &amp;lt;/math&amp;gt; и в случае достижения нужной точности - остановка.]]&lt;br /&gt;
Шаги алгоритма Арнольди выполняются строго последовательно, но вычисление &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;-ой невязки может происходить параллельно&lt;br /&gt;
с &amp;lt;math&amp;gt; (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;
Выполнение перечисленных операций занимает большую часть времени работы алгоритма GMRES. Поэтому при увеличении эффективности использования вычислительных ресурсов и ресурсов памяти вычислительной машины при выполнении этих операций повышается эффективность метода в целом. Достигается это применением при выполнении перечисленных операций аппарата параллельных вычислений.&lt;br /&gt;
&lt;br /&gt;
При выполнении параллельного алгоритма решения систем линейных алгебраических уравнений необходимо распределить входные данные наиболее рациональным способом. Матрица коэффициентов разбивается на непрерывные горизонтальные полосы. Распределение вектора правой части и начального приближения выполнено по принципу дублирования, т.е. все элементы векторов скопированы на все процессоры. Для рассматриваемой задачи решения СЛАУ такой подход распределения допустим, т.к. векторы содержат столько же элементов, сколько и одна строка или один столбец матрицы коэффициентов.&lt;br /&gt;
&lt;br /&gt;
Подзадачи можно разделить на 2 группы: операции между матрицей и вектором (например, умножение матрицы на вектор) и операции между двумя векторами (например, скалярное умножение). Подзадачи умножения константы на вектор и определение нормы вектора можно относить ко второй группе, так как их трудоемкость одного порядка.&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения рассматриваемых операций является, вектор, части которого расположены на участвовавших в вычислениях процессорах. Для объединения результатов расчета и получения полного вектора на каждом процессоре вычислительной системы необходимо выполнить операцию сбора данных.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; – квадратная матрица размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;-на-&amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
* &amp;lt;math&amp;gt; b &amp;lt;/math&amp;gt; – вектор правой части размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;; &lt;br /&gt;
* &amp;lt;math&amp;gt; x_0 &amp;lt;/math&amp;gt; – начальное приближение размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
* &amp;lt;math&amp;gt; \epsilon &amp;lt;/math&amp;gt; – погрешность решения.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для перезапускаемой версии алгоритма дополнительно:&#039;&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt; – число итераций.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt; n^2 + 2n + 1 &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: &lt;br /&gt;
* &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt; - вектор приближённого решения размера &amp;lt;math&amp;gt; n &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;
&lt;br /&gt;
Обобщенный метод минимальных невязок предназначен для решения несимметричных систем линейных уравнений. GMRES использует перезазапуски для контроля требований к хранению данных.&lt;br /&gt;
&lt;br /&gt;
Если используется неперезапускаемый метод, GMRES будет сходиться за не более &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов. Но это не имеет практического применения, когда &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; велико. Кроме того, требования к памяти и вычислениям при отсутствии перезапусков являются очень высокими. Важнейшим элементом для успешного применения &amp;lt;math&amp;gt; GMRES(m)&amp;lt;/math&amp;gt; являются перезапуски; то есть выбор &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt;. Существуют примеры, для которых метод застаивается и сходимость есть только на &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;-м шаге. Для таких систем, любой выбор &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt; меньше, чем &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - не сходится.&lt;br /&gt;
&lt;br /&gt;
Основным недостатком GMRES является то, что объемы работ и ресурсы памяти, требуемые для итерации, линейно возрастают с увеличением числа итераций. Если не удалось получить чрезвычайно быструю сходимость - затраты будут очень высокими. Основной способ преодолеть это ограничение - это перезапуск итерации. После выбранного числа итераций &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt; накопленные данные будут очищены и промежуточные результаты используются в качестве входных данных для последующих итераций. Эта процедура повторяется до тех пор, пока сходимость не будет достигнута. Трудность заключается в выборе подходящего значения &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt; слишком мало, &amp;lt;math&amp;gt;GMRES(m)&amp;lt;/math&amp;gt;  может быть медленно сходиться, или не сойтись совсем. Значение &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt;, большее, чем это необходимо, включает в себя чрезмерную работы и использует больше памяти. К сожалению, нет определенных правил, регулирующих выбор &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt;; выбирая , когда делать перезапуск - это вопрос опыта.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&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;ref&amp;gt;https://arxiv.org/pdf/1606.08740.pdf&amp;lt;/ref&amp;gt; и &amp;lt;ref&amp;gt;https://smartech.gatech.edu/bitstream/handle/1853/55635/PRATAPA-DISSERTATION-2016.pdf&amp;lt;/ref&amp;gt;.&lt;br /&gt;
Для исследования масштабируемости была использована параллельная реализация с использованием объекта KSP(решатель СЛАУ) бибилиотеки PETSc(содержащей структуры, типы данных и подпрограммы для параллельной реализации методов на подпространствах Крылова), найденная на GitHub &amp;lt;ref&amp;gt;https://github.com/erdc-cm/petsc-dev/tree/master/src/ksp/ksp/impls/gmres&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Вычисления проводились на вычислительном кластере, состоящем из 16 узлов, со следующей конфигурацией:&lt;br /&gt;
Altus 1804i Server - 4P Interlagos Node, Quad AMD Opteron 6276, 16C,&lt;br /&gt;
2.3 GHz, 128GB, DDR3-1333 ECC, 80GB SSD, MLC, 2.5&amp;quot; HCA, Mellanox ConnectX 2, 1-port QSFP, QDR, memfree, CentOS, Version 5.&lt;br /&gt;
&lt;br /&gt;
На рис. 2 представлен график сильной масштабируемости.&lt;br /&gt;
&lt;br /&gt;
[[File:scaling.JPG|thumb|center|500px|&#039;&#039;&#039;Рис. 2&#039;&#039;&#039; Зависимость производительности от числа процессоров (запуск производился на 1, 8, 27, 64, 216, 512, 1000 процессорах)]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Реализации алгоритма GMRES присутствуют во многих программных пакетах: &lt;br /&gt;
* [http://www.netlib.org/linpack/ LINPACK]&lt;br /&gt;
* [http://math.nist.gov/tnt/download.html/ JAMA/C++] &lt;br /&gt;
* [http://math-atlas.sourceforge.net/ ATLAS] &lt;br /&gt;
* [http://software.intel.com/mkl‎/ Intel MLK]&lt;br /&gt;
* [http://math.nist.gov/iml++/ IML++]&lt;br /&gt;
* [http://netlib.org/lapack/ LAPACK]&lt;br /&gt;
* [http://osl.iu.edu/research/mtl/ MTL]&lt;br /&gt;
* [http://www-users.cs.umn.edu/~saad/software/SPARSKIT/ SPARSKIT]&lt;br /&gt;
* [http://researcher.watson.ibm.com/researcher/view_group.php?id=1426 WSMP]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Alexander34396&amp;diff=19869</id>
		<title>Обсуждение участника:Alexander34396</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Alexander34396&amp;diff=19869"/>
		<updated>2016-12-02T02:43:01Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK) К вашей работе есть несколько замечаний по содержанию и вопросы по пункту с масштабируемостью. Новая серия замечаний стоит с моей подписью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.2.3 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;вычислить &amp;lt;math&amp;gt; r_m &amp;lt;/math&amp;gt; и остановиться,если требуемая точность была достигнута, иначе повторить.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как здесь предлагается оценивать достижение требуемой точности?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Умножение вектора на скаляр;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Деление вектора на скаляр.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В чем с вычислительной точки зрения принципиальная разница между умножением и делением вектора на скаляр? Деление всегда можно записать в виде умножение на обратную величину.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.5 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На практике используется перезапускаемая версия метода - GMRES(m):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Более распространенное название – версия GMRES с рестартами. Хорошо бы в этом разделе пояснить, почему «на практике используется» именно такая версия.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.6 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Если пренебречь сложностью вычисления &amp;lt;math&amp;gt; y_m &amp;lt;/math&amp;gt;, то общую сложность алгоритма GMRES можно разделить на две части:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно пояснить почему сложностью расчета &amp;lt;math&amp;gt; y_m &amp;lt;/math&amp;gt;  можно пренебречь.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.8 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;...нахождение взвешенной суммы векторов.&#039;&#039;&#039; Линейная комбинация векторов?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поэтому при увеличении эффективности использования вычислительных ресурсов и ресурсов памяти вычислительной машины при выполнении этих операций повышается эффективность метода в целом. Достигается это применением при выполнении перечисленных операций аппарата параллельных вычислений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Этот абзац не понятен и его нужно переформулировать. Например, применение параллельных вычислений не обязательно приводит к эффективности использованию вычислительных ресурсов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При выполнении параллельного алгоритма решения систем линейных алгебраических уравнений необходимо распределить входные данные наиболее рациональным способом. Матрица коэффициентов разбивается на непрерывные горизонтальные полосы. Распределение вектора правой части и начального приближения выполнено по принципу дублирования, т.е. все элементы векторов скопированы на все процессоры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Почему данный подход является «наиболее рациональным»? Например, n (размер вектора) может быть очень большим и вектор не будет помещаться в память одного процессора.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Результатом выполнения рассматриваемых операций является, вектор, части которого расположены на участвовавших в вычислениях процессорах. Для объединения результатов расчета и получения полного вектора на каждом процессоре вычислительной системы необходимо выполнить операцию сбора данных.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Требуются ли сборки данных в таком подходе на каждой итерации метода?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.10 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Если используется неперезапускаемый метод, GMRES будет сходиться за не более &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет просто сходиться с некоторой точностью, или в точной арифметике – это прямой метод за n шагов?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют примеры, для которых метод застаивается и сходимость есть только на &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;-м шаге. Для таких систем, любой выбор &amp;lt;math&amp;gt; m &amp;lt;/math&amp;gt; меньше, чем &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - не сходится.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Т.е. за n-1 шагов ошибка может быть сколь угодно большой? Нужно привести пример, ссылку или пояснить – в каком случае метод не сходится менее чем за n шагов?&lt;br /&gt;
&lt;br /&gt;
Опечатка - &#039;&#039;&#039;включает в себя чрезмерную работы&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 2.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:42, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Запускалась ли данная реализация GMRES в PETSc самостоятельно на указанном кластере?&lt;br /&gt;
&lt;br /&gt;
C чем связано то, что авторы работы [3] из списка литературы получили практически точно такой же график масштабируемости, но для предобусловленного метода GMRES, с помощью той же библиотеки PETSc и на том же самом кластере?&lt;br /&gt;
&lt;br /&gt;
Соответствует ли разбиение входных данных по параллельным процессам в реализации PETSc тому, что приведено в пункте 1.8? Описание алгоритма и то, что тестируется должно быть согласовано. Входит ли в замер времени счета описанная в пункте 1.8 сборка вектора решения на управляющем процессоре?&lt;br /&gt;
&lt;br /&gt;
Нужно также указать размерность задачи, описать структуру матрицы в экспериментах, условие на окончание итерационного процесса. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Добрый день. Начал проверять статью и оставил следующие заметки&lt;br /&gt;
&lt;br /&gt;
Здравствуйте. Немного исправил статью, исходя из ваших замечаний.&lt;br /&gt;
&lt;br /&gt;
= 1.2 = &lt;br /&gt;
На мой взгляд, нужны определения&lt;br /&gt;
span?&lt;br /&gt;
l2-норма?&lt;br /&gt;
&lt;br /&gt;
: [[Участник:Alexander34396|Alexander34396]] Дано пояснение обозначения span.Вместо l2-норма теперь используется Евклидова норма.&lt;br /&gt;
&lt;br /&gt;
= 1.2.1 = &lt;br /&gt;
Вот я читаю этот раздел как человек со стороны и вижу много формул. Почему они именно такие? В чем суть этого алгоритма?&lt;br /&gt;
&lt;br /&gt;
: [[Участник:Alexander34396|Alexander34396]] Перед алгоритмом добавлено описание идеи алгоритма и пояснения к формулам.&lt;br /&gt;
&lt;br /&gt;
= 1.2.2 = &lt;br /&gt;
Новые определения&lt;br /&gt;
&lt;br /&gt;
: [[Участник:Alexander34396|Alexander34396]] Добавлены некоторые пояснения.Добавлена ссылка на статью - вращения Гивенса.&lt;br /&gt;
&lt;br /&gt;
Затем я остановился, и у меня главные вопрос. Возможно ли сделать статью такой, чтобы для ее прочтения не требовалось обращаться к куче дополнительных источников? Вот я человек со стороны, хотя и заканчивал мехмат. Я могу разобраться со всем написанным здесь, но для этого мне придется гуглить кучу материалов. Но, насколько я понимаю, цель таких статей - быть более полными.&lt;br /&gt;
&lt;br /&gt;
: [[Участник:Alexander34396|Alexander34396]]  На мой взгляд, формат статей algo-wiki не подразумевает подробных объяснений и выводов формул, поэтому я добавил только некоторые пояснения, которые делают повествование более последовательным и несколько более понятным. При этом для полного понимания описанного метода для человека со стороны всё равно придётся обращаться к сторонним источникам.&lt;br /&gt;
&lt;br /&gt;
Можете или добавить объяснений или возразить мне. В любом случае, пока с прочтением остановился, жду ответа или исправление (а лучше и того, и другого)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= 2.4 = &lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 19:09, 30 ноября 2016 (MSK) &#039;&#039;&#039;принято&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lvs/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B_%D0%BB%D0%B8%D0%BD%D0%B5%D0%B9%D0%BD%D1%8B%D1%85_%D0%B0%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D1%83%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9_GMRES&amp;diff=19868</id>
		<title>Участник:Lvs/Итерационный метод решения системы линейных алгебраических уравнений GMRES</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lvs/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B_%D0%BB%D0%B8%D0%BD%D0%B5%D0%B9%D0%BD%D1%8B%D1%85_%D0%B0%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D1%83%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9_GMRES&amp;diff=19868"/>
		<updated>2016-12-02T02:19:44Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Итерационный метод решения системы линейных алгебраических уравнений GMRES (или обобщенный метод минимальных невязок) используется для решения систем линейных алгебраических уравнений с заданной точностью приближения. Метод основан на процессе Арнольди, посредст­вом которого матрица СЛАУ приводится к (верхней) хессенберговой форме.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
Дана система линейных алгебраических уравнений &amp;lt;math&amp;gt;Ax = b&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; - квадратная матрица размера &amp;lt;math&amp;gt;n \times n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вычисляется последовательность приближённых решений уравнения &amp;lt;math&amp;gt; x_m &amp;lt;/math&amp;gt;, которая сходится к точному решению уравнения &amp;lt;math&amp;gt;x^*&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Подпространство Крылова размерности &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;, порожденное вектором &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; и матрицей &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; – линейное пространство&lt;br /&gt;
&amp;lt;math&amp;gt;K_m(A, v)&amp;lt;/math&amp;gt;, являющееся линейной оболочкой векторов &amp;lt;math&amp;gt;b, Ab, A^2b, ..., A^{m-1}b&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приближённое решение считается по формуле &amp;lt;math&amp;gt; x_m = Q_my_m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;Q_m&amp;lt;/math&amp;gt; - матрица размера &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;, составленная из векторов ортонормированного базиса пространства &amp;lt;math&amp;gt;K_m(A, v)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;y_m \in \mathbb{R}^m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итоговым считается решение, минимизирующее норму невязки (&amp;lt;math&amp;gt;||r||_2 = ||b - Ax_m||_2&amp;lt;/math&amp;gt;) с заданной точностью.&lt;br /&gt;
&lt;br /&gt;
Для вычисления векторов ортонормированного базиса используется алгоритм Арнольди:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
q[1] = b/||b||&lt;br /&gt;
for j = 1, ..., n-1 do&lt;br /&gt;
    z = Aq[j]; //очередной вектор&lt;br /&gt;
    for i = 1,..., j do&lt;br /&gt;
        h[i][j] = (z, q[i]);&lt;br /&gt;
        z = z − h[i][j]q[i];&lt;br /&gt;
    end i&lt;br /&gt;
    h[j+1][j] = ||z||;&lt;br /&gt;
    if (h[j+1][j] == 0) break;&lt;br /&gt;
    q[j+1] = z/h[j+1][j];&lt;br /&gt;
end j&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Сложность алгоритма &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На каждом шаге алгоритма получаются векторы &amp;lt;math&amp;gt;q_1, q_2, ..., q_m&amp;lt;/math&amp;gt;, являющиеся ортонормированным базисом Крыловского пространства &amp;lt;math&amp;gt;K_m(A, b)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Значения &amp;lt;math&amp;gt;h_{i,j}&amp;lt;/math&amp;gt; образуют верхнюю матрицу Хессенберга (обозначим как &amp;lt;math&amp;gt;H_m&amp;lt;/math&amp;gt;, размерность &amp;lt;math&amp;gt;m+1 \times m&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H_k = \begin{bmatrix}h_{11} &amp;amp; h_{12} &amp;amp; h_{13} &amp;amp;... &amp;amp; h_{1m-1} &amp;amp; h_{1m} \\ h_{21} &amp;amp; h_{22} &amp;amp; h_{23} &amp;amp; ... &amp;amp; h_{2m-1} &amp;amp; h_{2m} \\ 0 &amp;amp; h_{32} &amp;amp; h_{33} &amp;amp;...&amp;amp; h_{3m-1} &amp;amp; h_{3m} \\ ... &amp;amp; ... &amp;amp; ... &amp;amp; ... &amp;amp; ... &amp;amp; ... \\ 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; ... &amp;amp; h_{m m-1} &amp;amp; h_{mm} \\0 &amp;amp; 0 &amp;amp; 0 &amp;amp; ... &amp;amp; 0 &amp;amp; h_{m+1 m}\end{bmatrix}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Вектор невязки задан уравнением &amp;lt;math&amp;gt;r_m = H_my_m - ||b - Ax_0||e_1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;x_0&amp;lt;/math&amp;gt; - вектор начального приближения. Минимизация второй нормы вектора невязки представляет из себя решение линейной задачи минимальных квадратов размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приближённое решение вычисляется по формуле &amp;lt;math&amp;gt; x_m = Q_my_m&amp;lt;/math&amp;gt; после нахождения соответствующего значения минимизирующего вторую невязку вектора. Сложность вычислений &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
Самая трудоёмкая и самая часто вызываемая операция в алгоритме - умножение матрицы на вектор. В первую очередь это связано с вычислением матрицы Хессенберга.&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
# Алгоритм Арнольди&lt;br /&gt;
# Решение линейной задачи минимальных квадратов&lt;br /&gt;
# Вычисление решения&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
    Вычислить ортонормированный базис размера m&lt;br /&gt;
    Вычислить минимальное приближение&lt;br /&gt;
    if (приближение &amp;lt; заданная точность)&lt;br /&gt;
        Вычислить результат&lt;br /&gt;
        return;&lt;br /&gt;
    else&lt;br /&gt;
        Повторить для m = m+1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Сложность вычислений собственных векторов на каждом шаге - &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;, но может уменьшиться до &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; при более разреженной матрице.&lt;br /&gt;
&lt;br /&gt;
Сложность решения задачи минимальных квадратов &amp;lt;math&amp;gt;O(m^2)&amp;lt;/math&amp;gt;, но при последовательном выполнении алгоритма можно понизить сложность до &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt; путём использования подсчитанных на прошлых итерациях значений.&lt;br /&gt;
&lt;br /&gt;
Сложность вычисления решения &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;, поэтому его целесообразно вычислять только в конце.&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Основной ресурс параллелизма - умножение матрицы на вектор, поскольку является самым ресурсоёмким, но при этом умножать отдельные строки матрицы можно независимо друг от друга. Для этой операции информационный граф представлен на рисунке.&lt;br /&gt;
&lt;br /&gt;
[[file:GraphLvs2FM.jpg|thumb|center|700px|Рис.1. Информационный граф умножения матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
# Параллельное умножение матрицы на вектор выполняется в &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ярусов умножений и сложений.&lt;br /&gt;
# Шаги алгоритма Арнольди выполняются строго последовательно, однако последующее нахождение невязки можно выполнять параллельно с запуском следующего шага алгоритма.&lt;br /&gt;
# Сложность решения задачи минимальных квадратов зависит от используемого алгоритма. В отличие от последовательного метода данные, полученные на прошлых шагах здесь использовать нельзя.&lt;br /&gt;
# Вычисление результата выполняется один раз, его можно выполнить параллельно в &amp;lt;math&amp;gt; n &amp;lt;/math&amp;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;b&amp;lt;/math&amp;gt;, точность &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;. Объём: &amp;lt;math&amp;gt;n^2 + n + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; Вектор &amp;lt;math&amp;gt;x_m&amp;lt;/math&amp;gt;. Объём: &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
Теоретически на каждой итерации алгоритма сложность вычислений составляет &amp;lt;math&amp;gt;n + X&amp;lt;/math&amp;gt; операций умножения, где &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; - сложность алгоритма для решения задачи минимальных квадратов. Таким образом в худшем случае сложность будет примерно равна &amp;lt;math&amp;gt;n^2 + X*n + n&amp;lt;/math&amp;gt; операций умножения.&lt;br /&gt;
&lt;br /&gt;
Несмотря на то, что в теории итерации алгоритма можно выполнять параллельно после выполнения алгоритма Арнольди, на практике необходимая точность может быть достигнута раньше чем на n-й итерации, что потребует какого-нибудь способа прервать последующие итерации. Для избегания лишних вычисление возможно оптимально оставить эту часть последовательной.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
Для исследования масштабируемости алгоритма была использована параллельная реализация, найденная на просторах GitHub&amp;lt;ref&amp;gt;Parallel GMRES Algorithm for Solving Giant Sparse System of Linear Equations https://github.com/arrgasm/paraGMRES/&amp;lt;/ref&amp;gt;. Программа была запущена на суперкомпьютере BlueGene на разреженной матрице размера 90448х90448. Параметрами запуска являются 100 итераций алгоритма и 10 перезапусков алгоритм (повторный запуск алгоритма с использованием решения, полученного на предыдущем запуске, в качестве начального приближения). График зависимости времени выполнения от числа процессоров представлен на рисунке 2.&lt;br /&gt;
[[file:PlotLvs1.png|thumb|center|400px|Рис 2. График зависимости времени выполнения от числа процессоров]]&lt;br /&gt;
График эффективности для полученного времени выполнения указан на рисунке 3.&lt;br /&gt;
[[file:PlotLvs2.png|thumb|center|400px|Рис 3. График зависимости эффективности реализации от числа процессоров]]&lt;br /&gt;
Параметры компиляции:&lt;br /&gt;
&amp;lt;code&amp;gt;mpixlc_r -qsmp=omp -O3&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметры запуска:&lt;br /&gt;
&amp;lt;code&amp;gt;gmres mat.mtx void 100 0 10&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
Реализации алгоритма GMRES присутствуют во многих программных продуктах как части стандартных библиотек, например Matlab или DEFORM3D. Также существую отдельные библиотеки, например MGMRES для языка С++.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Тыртышников Е. Е. Методы численного анализа — М., Академия, 2007.&lt;br /&gt;
&lt;br /&gt;
[2] М. Дана, А. Г. Зыков, Х. Д. Икрамов Метод минимальных невязок для специального класса линейных систем с нормальными матрицами коэффициентов - Ж. вычисл. матем. и матем. физ., 2005, том 45, номер 11&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lvs&amp;diff=19867</id>
		<title>Обсуждение участника:Lvs</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lvs&amp;diff=19867"/>
		<updated>2016-12-02T02:19:31Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) Хорошая работа, нужно исправить несколько замечаний по содержанию. Новая серия замечаний стоит с моей подписью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Итерационный метод решения системы линейных алгебраических уравнений GMRES (или обобщенный метод минимальных невязок) используется для решения систем линейных алгебраических уравнений с заданной точностью приближения.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Дважды повторяется, что GMRES – метод решения систем линейных уравнений. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;z = Aq[j]; //очередной вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь Aq[j] в рамках обозначений выше?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Индексы в определении матрицы Хессенберга не согласованы (матрица &amp;lt;math&amp;gt;H_k&amp;lt;/math&amp;gt;, элементы – &amp;lt;math&amp;gt;h_{mm}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
Нужно привести какие еще матрично-векторные операции входят в алгоритм. &lt;br /&gt;
Сколько раз требуется выполнить матрично-векторное умножение и, например, расчет скалярных произведений двух векторов?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вычислить минимальное приближение&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь подразумевается под минимальным приближением?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сложность вычислений собственных векторов на каждом шаге - &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;, но может уменьшиться до &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; при более разреженной матрице.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это утверждение нужно пояснить. Получается так, что если увеличивать размерность матрицы, то на каком-то шаге измениться степень в оценке сложности (размер будет расти как n^2, число ненулевых элементов, например, как n, и матрица будет «более разреженной»)? С чем это связано?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Несмотря на то, что в теории итерации алгоритма можно выполнять параллельно после выполнения алгоритма Арнольди, на практике необходимая точность может быть достигнута раньше чем на n-й итерации, что потребует какого-нибудь способа прервать последующие итерации. Для избегания лишних вычисление возможно оптимально оставить эту часть последовательной.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Какую здесь часть лучше оставить последовательной – проверку достижения сходимости или прерывания итераций? Почему оптимально оставлять ее последовательной?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
Нужно дополнить раздел описанием структуры матрицы, выбранной для численных экспериментов; помимо размера матрицы, привести число ненулевых элементов в ней; описать то, как реализовано разбиение данных по параллельным процессам в выбранной реализации GMRES.&lt;br /&gt;
&lt;br /&gt;
В тексте нужно уточнить достигается ли сходимость при 100 итерациях. Почему были выбраны именно такие параметры – 100 итераций и 10 рестартов?&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.2 =&lt;br /&gt;
Это определение пространства Крылова?&lt;br /&gt;
Не совсем понятно описание алгоритма, если не знаешь, о чем речь&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 =&lt;br /&gt;
Он достаточно длинный. Посмотрите описания готовых алгоритмов на алговики. Псевдокод здесь не читается, ядро должно лучше восприниматься&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.4 =&lt;br /&gt;
Если макроструктура это указанные 3 пункта, то нужно пояснить, почему именно пункт 1 является ядром. Он самый ресурсоемкий?&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 =&lt;br /&gt;
Почему это основной ресурс. Это основная операция в алгоритме? Требуются пояснения&lt;br /&gt;
&lt;br /&gt;
^^ эти пункты я тоже редактировал (как-то)&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 14:03, 23 ноября 2016 (MSK) &#039;&#039;&#039;принято&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lvs&amp;diff=19866</id>
		<title>Обсуждение участника:Lvs</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lvs&amp;diff=19866"/>
		<updated>2016-12-02T02:16:27Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) Хорошая работа, нужно исправить несколько замечаний по содержанию. Новая серия замечаний стоит с моей подписью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Итерационный метод решения системы линейных алгебраических уравнений GMRES (или обобщенный метод минимальных невязок) используется для решения систем линейных алгебраических уравнений с заданной точностью приближения.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Дважды повторяется, что GMRES – метод решения систем линейных уравнений. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;z = Aq[j]; //очередной вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь Aq[j] в рамках обозначений выше?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Индексы в определении матрицы Хессенберга не согласованы (матрица &amp;lt;math&amp;gt;H_k&amp;lt;/math&amp;gt;, элементы – &amp;lt;math&amp;gt;h_{mm}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
Нужно привести какие еще матрично-векторные операции входят в алгоритм. &lt;br /&gt;
Сколько раз требуется выполнить матрично-векторное умножение и, например, расчет скалярных произведений двух векторов?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вычислить минимальное приближение&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь подразумевается под минимальным приближением?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сложность вычислений собственных векторов на каждом шаге - &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;, но может уменьшиться до &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; при более разреженной матрице.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это утверждение нужно пояснить. Получается так, что если увеличивать размерность матрицы, то на каком-то шаге измениться степень (размер будет расти как n^2, число ненулевых элементов, например, как n, и матрица будет «более разреженной»)? С чем это связано?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Несмотря на то, что в теории итерации алгоритма можно выполнять параллельно после выполнения алгоритма Арнольди, на практике необходимая точность может быть достигнута раньше чем на n-й итерации, что потребует какого-нибудь способа прервать последующие итерации. Для избегания лишних вычисление возможно оптимально оставить эту часть последовательной.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Какую здесь часть лучше оставить последовательной – проверку достижения сходимости или прерывания итераций? Почему оптимально оставлять ее последовательной?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 05:15, 2 декабря 2016 (MSK) &lt;br /&gt;
&lt;br /&gt;
Нужно дополнить раздел описанием структуры матрицы, выбранной для численных экспериментов; помимо размера матрицы, привести число ненулевых элементов в ней; описать то, как реализовано разбиение данных по параллельным процессам в выбранной реализации GMRES.&lt;br /&gt;
&lt;br /&gt;
В тексте нужно уточнить достигается ли сходимость при 100 итерациях. Почему были выбраны именно такие параметры – 100 итераций и 10 рестартов?&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.2 =&lt;br /&gt;
Это определение пространства Крылова?&lt;br /&gt;
Не совсем понятно описание алгоритма, если не знаешь, о чем речь&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 =&lt;br /&gt;
Он достаточно длинный. Посмотрите описания готовых алгоритмов на алговики. Псевдокод здесь не читается, ядро должно лучше восприниматься&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.4 =&lt;br /&gt;
Если макроструктура это указанные 3 пункта, то нужно пояснить, почему именно пункт 1 является ядром. Он самый ресурсоемкий?&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 =&lt;br /&gt;
Почему это основной ресурс. Это основная операция в алгоритме? Требуются пояснения&lt;br /&gt;
&lt;br /&gt;
^^ эти пункты я тоже редактировал (как-то)&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 14:03, 23 ноября 2016 (MSK) &#039;&#039;&#039;принято&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Blizn/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80.&amp;diff=19865</id>
		<title>Участник:Blizn/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор.</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Blizn/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80.&amp;diff=19865"/>
		<updated>2016-12-01T23:56:21Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(l)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2l+m+n+1&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;
Выполнила: [[Участник:Blizn|И.В. Близнякова]] (611 группа).&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988.&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
* есть &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
* в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
* ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
* таково, что для данного алгоритма и вычислительной системы имеет смысл извлекать выгоду из наличия в ней нулей.&lt;br /&gt;
&lt;br /&gt;
=== Хранение разреженной матрицы ===&lt;br /&gt;
==== Формат RR(C)O ====&lt;br /&gt;
Рассмотрим сначала формат &#039;&#039;&#039;RR(C)O&#039;&#039;&#039;. Сокращенное название данного формата происходит от английского словосочетания &#039;&#039;&amp;quot;Row - wise Representation Complete and Ordered&amp;quot;&#039;&#039; (строчное представление, полное и упорядоченное). В данном формате вместо одного двумерного массива, используются три одномерных. Значения ненулевых элементов матрицы и соответствующие им столбцовые индексы хранятся в этом формате по строкам в двух массивах &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Массив указателей &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, используется для ссылки на компоненты массивов &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, с которых начинается описание очередной строки. Последняя компонента массива &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; содержит указатель первой свободной компоненты в массивах &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, т.е. равна числу ненулевых элементов матрицы, увеличенному на единицу. Здесь уместно привести пример.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим матрицу &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 0 \\&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 6 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
тогда ее представление в формате &#039;&#039;&#039;RR(C)O&#039;&#039;&#039; будет иметь вид:&lt;br /&gt;
   IA = [ 1 2 4 4 5 6 ]&lt;br /&gt;
   JA = [ 4 1 3 2 3 ]&lt;br /&gt;
   AN = [ 2 1 3 6 4 ]&lt;br /&gt;
Т.е. массив &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; содержит все не нулевые элементы исходной матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; номер столбца в котором находится соответствующий элемент из &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и наконец массив &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; содержит номер с которого начинается описание элементов в массивах &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Таким образом информация об элементах 2-ой строки матрицы хранится в элементах с &amp;lt;math&amp;gt;IA[2] = 2&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;IA[3] - 1 = 3&amp;lt;/math&amp;gt; включительно массивов &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Можно обратить внимание, что &amp;lt;math&amp;gt;IA[3] = IA[4] = 4&amp;lt;/math&amp;gt;, а это означает, что 3-я строка матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; нулевая.&lt;br /&gt;
&lt;br /&gt;
В общем случае описание &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;-й строки матрицы A хранится в компонентах с &amp;lt;math&amp;gt;IA[r]&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA[r + 1] - 1&amp;lt;/math&amp;gt; включительно массивов &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;IA[r + 1] = IA[r]&amp;lt;/math&amp;gt;, то это означает, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;-я строка нулевая. Количество элементов в массиве &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; на единицу больше, чем число строк исходной матрицы, а количество элементов в массивах &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; равно числу ненулевых элементов исходной матрицы.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют &#039;&#039;полным&#039;&#039;, поскольку представлена вся матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, &#039;&#039;упорядоченным&#039;&#039;, поскольку элементы каждой строки матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; хранятся в соответствии с возрастанием столбцовых индексов, и строчным, поскольку информация о матрице &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; указывается по строкам.&lt;br /&gt;
&lt;br /&gt;
Массивы &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; представляют портрет (структуру) матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, задаваемый как множество списков смежности ассоциированного с &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; графа. Если алгоритм, реализующий какую-либо операцию над разреженными матрицами, разбит на этапы символической обработки, на котором определяется портрет результирующей матрицы, и численной обработки, на котором определяются значения элементов результирующей матрицы, то массивы &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; заполняются на первом этапе, а массив &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; - на втором.&lt;br /&gt;
&lt;br /&gt;
==== Формат RR(C)U ====&lt;br /&gt;
 &lt;br /&gt;
Рассмотрим теперь формат &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Сокращенное название данного формата происходит от английского словосочетания &#039;&#039;&amp;quot;Row - wise Representation Complete and Unordered&amp;quot;&#039;&#039; (строчное представление, полное, но неупорядоченное). Формат &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; отличается от &#039;&#039;&#039;RR(C)O&#039;&#039;&#039; тем, что в данном случае соблюдается упорядоченность строк, но внутри каждой строки элементы исходных матриц могут храниться в произвольном порядке. Для матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; нашего примера вполне можно было бы использовать и строчное представление, полное, но неупорядоченное такое:&lt;br /&gt;
   IA = [ 1 2 4 4 5 6 ]&lt;br /&gt;
   JA = [ 4 3 1 2 3 ]&lt;br /&gt;
   AN = [ 2 1 3 6 4 ]&lt;br /&gt;
Такие неупорядоченные представления могут быть очень удобны в практических вычислениях. Результаты большинства матричных операций получаются неупорядоченными, а их упорядочение стоило бы значительных затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы их представления были упорядоченными.&lt;br /&gt;
&lt;br /&gt;
==== Замечания ====&lt;br /&gt;
&lt;br /&gt;
Несколько замечаний по поводу рассмотренных форматов представления:&lt;br /&gt;
# Очевидно, что представление матрицы в формате &#039;&#039;&#039;RR(C)O&#039;&#039;&#039; так же является и представлением в формате &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, но не наоборот.&lt;br /&gt;
# Из представления матрицы в формате &#039;&#039;&#039;RR(C)&#039;&#039;&#039; нельзя получить информацию о точном количестве столбцов исходной матрицы.&lt;br /&gt;
# Целесообразно (в вопросе экономии памяти) использовать представления &#039;&#039;&#039;RR(C)&#039;&#039;&#039; в случае, если матрица содержит значительное число нулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Умножение разреженной матрицы на вектор ===&lt;br /&gt;
&lt;br /&gt;
Важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &lt;br /&gt;
&lt;br /&gt;
Мы рассмотрим умножение разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; посредством массивов &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; на заполненный вектор-столбец.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Исходные данные: разреженная матрица общего вида &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;i = 1,...,n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j = 1,...,m&amp;lt;/math&amp;gt;). Заполненный вектор-столбец &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;j =1,...,m&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: заполненный вектор-столбец &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;i = 1,...,n&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Формулы метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{l_{i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;l_{i}&amp;lt;/math&amp;gt; - количество ненулевых элементов строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j(k)&amp;lt;/math&amp;gt; - индекс &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;-го ненулевого элемента матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
Вычислительное ядро последовательной версии умножения разреженной матрицы на вектор можно составить из множественных (всего их &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) вычислений скалярных произведений строк матрицы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{l_{i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Как записано и в [[#Вычислительное ядро алгоритма|описании ядра алгоритма]], основную часть метода составляют множественные (всего &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) вычисления сумм:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{l_{i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
которые могут вычисляться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Далее предполагаем, что разреженная матрица общего вида &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; хранится в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; посредством массивов &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;.&lt;br /&gt;
Последовательность исполнения метода следующая:&lt;br /&gt;
&lt;br /&gt;
Выполнять для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; &lt;br /&gt;
# &amp;lt;math&amp;gt;c_{i} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;math&amp;gt;IAA = IA[i]&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;math&amp;gt;IAB = IA[i + 1] - 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = IAA}^{IAB} AN[k]b_{JA[k]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
После этого (если &amp;lt;math&amp;gt;i \le n&amp;lt;/math&amp;gt;) происходит переход к шагу 1 с бо́льшим &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для умножения разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, размером &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt; на заполненный вектор &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
Умножения и сложения составляют &#039;&#039;основную часть алгоритма&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
При классификации по последовательной сложности, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам &amp;lt;math&amp;gt;O(l)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Опишем [[глоссарий#Граф алгоритма|граф алгоритма]]&amp;lt;ref&amp;gt;Воеводин В.В.  Математические основы параллельных вычислений// М.: Изд. Моск. ун-та, 1991. 345 с.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002. – 608 с.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Фролов А.В.. Принципы построения и описание языка Сигма. Препринт ОВМ АН N 236. М.: ОВМ АН СССР, 1989.&amp;lt;/ref&amp;gt; как аналитически, так и в виде рисунка.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
Первая группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Естественно введённые координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, принимая все целочисленные значения,&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = IA[i+1]-IA[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; - элемент &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;AN[IA_{i}+j-1]&amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; - элемент &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;b[IA_{i}+j-1]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;промежуточным данным&#039;&#039; алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Естественно введённые координаты области таковы: &lt;br /&gt;
* &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения,&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = IA[i+1]-IA[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;j = 1&amp;lt;/math&amp;gt; - результат срабатывания операции, соответствующей вершине из первой группы, с координатами &amp;lt;math&amp;gt;(i, j)&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;j &amp;gt; 1&amp;lt;/math&amp;gt; - результат срабатывания операции, соответствующей вершине из второй группы, с координатами &amp;lt;math&amp;gt;(i, j - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
* &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из первой группы, с координатами &amp;lt;math&amp;gt;(i, j + 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции:&lt;br /&gt;
* при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;промежуточным данным&#039;&#039; алгоритма;&lt;br /&gt;
* при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф можно посмотреть на рис.1. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
[[file:Bliznalg.png|thumb|center|1000px|Рисунок 1. Граф алгоритма умножения разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для умножения разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, размерности &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt; на заполненный вектор &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt; в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* Не более чем &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; сложений и умножений (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вычислений в каждом из ярусов)&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;. При классификации по ширине ЯПФ его сложность будет &amp;lt;math&amp;gt;O(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;n \times m&amp;lt;/math&amp;gt;, хранимая в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; посредством массивов &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Заполненный вектор-столбец &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;2l+m+n+1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; - количество ненулевых элементов в матрице &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: заполненный вектор-столбец &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; с элементами &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;i = 1,...,n&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;.&lt;br /&gt;
&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – &#039;&#039;константа&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; - количество ненулевых элементов матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;. Пусть &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; - объем памяти, используемый для хранения значения элемента матрицы, &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; - объём памяти, используемый для хранения номера столбца или строки. В таком случае для хранения матрицы в стандартном представлении нам потребуется объем памяти, равный &amp;lt;math&amp;gt;x \cdot n \cdot m&amp;lt;/math&amp;gt;, для хранения в формате &#039;&#039;&#039;RR(C)&#039;&#039;&#039; - &amp;lt;math&amp;gt;y(n + 1) + (x + y)l&amp;lt;/math&amp;gt;. Таким образом хранение в формате &#039;&#039;&#039;RR(C)&#039;&#039;&#039; не является эффективным для матриц, в которых &amp;lt;math&amp;gt;l &amp;gt; \frac{xnm - y(n+1)}{x+y}&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;
# Каждый процессор считывает входные данные из файла, зависящего от его номера. Данные имеют вид: вектор &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; и набор определённых строк матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в формате &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; в зависимости от номера процессора и их числа;&lt;br /&gt;
# Процессоры проводят вычисления значений вектора &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; в зависимости от имеющихся данных;&lt;br /&gt;
# Все процессоры отправляют результаты вычисления процессору, выбранному главным, и главный процессор выводит результат вычислений.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot; style=&amp;quot;width:100%&amp;quot;&amp;gt;&lt;br /&gt;
Текст использованной в экспериментах реализации (язык &#039;&#039;С++&#039;&#039;):&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;sstream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;iterator&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef std::shared_ptr&amp;lt;std::vector&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt; &amp;gt; MyData;&lt;br /&gt;
&lt;br /&gt;
MyData ReadData(const std::string&amp;amp; data_path) {&lt;br /&gt;
  std::ifstream file_stream;&lt;br /&gt;
  MyData retval(new std::vector&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;());&lt;br /&gt;
  file_stream.open(data_path);&lt;br /&gt;
&lt;br /&gt;
  while (!file_stream.eof()) {&lt;br /&gt;
    std::string str;&lt;br /&gt;
    std::getline(file_stream, str);&lt;br /&gt;
&lt;br /&gt;
    std::istringstream iss(str);&lt;br /&gt;
    auto temp_1 = (std::istream_iterator&amp;lt;std::string&amp;gt;(iss));&lt;br /&gt;
    auto temp_2 =  (std::istream_iterator&amp;lt;std::string&amp;gt;());&lt;br /&gt;
&lt;br /&gt;
    std::vector&amp;lt;std::string&amp;gt; coordinates{ temp_1, temp_2};&lt;br /&gt;
retval-&amp;gt;push_back(std::vector&amp;lt;int&amp;gt;());&lt;br /&gt;
    for (auto&amp;amp; e : coordinates) {&lt;br /&gt;
      retval-&amp;gt;back().push_back(std::stoi(e));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return retval;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// input: vector b, vector ia, vector ja, vector an&lt;br /&gt;
int main(int argc, char** argv){&lt;br /&gt;
	MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
	int pid, np;&lt;br /&gt;
	MPI_Status *s = new MPI_Status;&lt;br /&gt;
	MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;pid);&lt;br /&gt;
	MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;np);&lt;br /&gt;
	if (argc == 2){&lt;br /&gt;
		int n;&lt;br /&gt;
		int indx = 0;&lt;br /&gt;
		int stp;&lt;br /&gt;
                double strttime = MPI_Wtime();&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; b;&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; ia;&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; ja;&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; an;&lt;br /&gt;
                auto data = ReadData(&amp;quot;data_&amp;quot; + std::to_string(static_cast&amp;lt;long long&amp;gt;(pid)) + &amp;quot;.txt&amp;quot;);&lt;br /&gt;
	        b = (*data)[0];&lt;br /&gt;
		ia = (*data)[1];&lt;br /&gt;
		ja = (*data)[2];&lt;br /&gt;
		an = (*data)[3];&lt;br /&gt;
		n = (*data)[0].size();&lt;br /&gt;
		std::vector&amp;lt;int&amp;gt; c; &lt;br /&gt;
                stp = n / np + ((n % np &amp;gt; pid) ? 1 : 0);&lt;br /&gt;
		if (pid == 0){&lt;br /&gt;
			c.resize(n, 0);&lt;br /&gt;
		}&lt;br /&gt;
		else{&lt;br /&gt;
			c.resize(stp, 0);&lt;br /&gt;
		}&lt;br /&gt;
		for (int i = 0; i &amp;lt; stp; i++){&lt;br /&gt;
			int strt = ia[i] - ia[0];&lt;br /&gt;
                        int lstr = ia[i + 1] - ia[i];&lt;br /&gt;
			for (int j = 0; j &amp;lt; lstr; j++){&lt;br /&gt;
				c[i] += an[strt + j] * b[ja[strt + j]];&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		if (pid == 0){&lt;br /&gt;
			for (int i = 1; i &amp;lt; np; i++){&lt;br /&gt;
				indx += n / np + ((n % np &amp;gt; i - 1) ? 1 : 0);&lt;br /&gt;
				stp = n / np + ((n % np &amp;gt; i) ? 1 : 0);&lt;br /&gt;
				MPI_Recv(&amp;amp;c[indx], stp, MPI_INT, i, 0, MPI_COMM_WORLD, s);&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		else{&lt;br /&gt;
			MPI_Send(&amp;amp;c[0], stp, MPI_INT, 0, 0, MPI_COMM_WORLD);&lt;br /&gt;
		}&lt;br /&gt;
		if (pid == 0){&lt;br /&gt;
			for (int e : c) {&lt;br /&gt;
                std::cout &amp;lt;&amp;lt; e &amp;lt;&amp;lt; &amp;quot;\n&amp;quot;;&lt;br /&gt;
                        }&lt;br /&gt;
                        double endtime = MPI_Wtime();&lt;br /&gt;
                        std::cout &amp;lt;&amp;lt; &amp;quot;Success! Time = &amp;quot; &amp;lt;&amp;lt; endtime - strttime &amp;lt;&amp;lt; &amp;quot;\n&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	MPI_Finalize();&lt;br /&gt;
	return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot; style=&amp;quot;width:100%&amp;quot;&amp;gt;&lt;br /&gt;
Для формирования входных данных использовался следующий алгоритм (язык &#039;&#039;Python&#039;&#039;):&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from scipy import sparse as sp&lt;br /&gt;
from numpy.random import randint&lt;br /&gt;
from os import mkdir&lt;br /&gt;
from os.path import join as jn&lt;br /&gt;
&lt;br /&gt;
n = 10000&lt;br /&gt;
np = [1, 2, 4, 8, 16, 32, 64, 128]&lt;br /&gt;
&lt;br /&gt;
a = sp.csr_matrix(randint(0, 2, (n, n)))&lt;br /&gt;
b = randint(1, 5, n)&lt;br /&gt;
i = 0&lt;br /&gt;
&lt;br /&gt;
for j in np:&lt;br /&gt;
  mkdir(&#039;data_&#039; + str(j))&lt;br /&gt;
  indx = 0&lt;br /&gt;
  for i in range(0, j):&lt;br /&gt;
    stp = n / j + (1 if (n % j &amp;gt; i) else 0)&lt;br /&gt;
    ael = a.indptr[indx + stp] - a.indptr[indx]&lt;br /&gt;
    strt = a.indptr[indx]&lt;br /&gt;
    with open(jn(&#039;data_&#039; + str(j), &#039;data_&#039; + str(i) + &#039;.txt&#039;), &#039;w&#039;) as fout:&lt;br /&gt;
    &lt;br /&gt;
      for e in b:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
	&lt;br /&gt;
      s = a.indptr[indx:indx + stp + 1]&lt;br /&gt;
      for e in s:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
	&lt;br /&gt;
      s = a.indices[strt:strt + ael]&lt;br /&gt;
      for e in s:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
    &lt;br /&gt;
      s = a.data[strt:strt + ael]&lt;br /&gt;
      for e in s:&lt;br /&gt;
        fout.write(&#039;{0} &#039;.format(e))&lt;br /&gt;
      fout.write(&#039;\n&#039;)&lt;br /&gt;
  &lt;br /&gt;
    indx = indx + n / j + (1 if (n % j &amp;gt; i) else 0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма умножения разреженной матрицы на вектор. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Входные данные формировались на персональном компьютере в силу того, что интерпретатор на суперкомпьютере &amp;quot;Ломоносов&amp;quot; не удовлетворял нужным требованиям, и потом отправлялись на суперкомпьютер для последующей обработки.&lt;br /&gt;
&lt;br /&gt;
Программа была собрана на узле компиляции суперкомпьютера &amp;quot;Ломоносов&amp;quot;, с помощью компилятора &#039;&#039;intel/15.0.090&#039;&#039; и компилятора &#039;&#039;openmpi/1.6.5-icc&#039;&#039;, на языке &#039;&#039;С++11&#039;&#039;.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot; style=&amp;quot;width:100%&amp;quot;&amp;gt;&lt;br /&gt;
Сборка производилась с помощью &#039;&#039;CMakeLists.txt&#039;&#039;, его содержание прилагается:&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cmake_minimum_required(VERSION 2.8)&lt;br /&gt;
&lt;br /&gt;
project(task1)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_STANDARD 11)&lt;br /&gt;
&lt;br /&gt;
set(CXX_STANDARD_REQUIRED)&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_C_COMPILER mpicc)&lt;br /&gt;
set(CMAKE_CXX_COMPILER mpicxx)&lt;br /&gt;
&lt;br /&gt;
find_package(MPI REQUIRED)&lt;br /&gt;
&lt;br /&gt;
include_directories(${MPI_INCLUDE_PATH})&lt;br /&gt;
&lt;br /&gt;
SET(CMAKE_CXX_COMPILER mpicc)&lt;br /&gt;
&lt;br /&gt;
if(MPI_COMPILE_FLAGS)&lt;br /&gt;
  set_target_properties(task1 PROPERTIES&lt;br /&gt;
    COMPILE_FLAGS &amp;quot;${MPI_COMPILE_FLAGS}&amp;quot;)&lt;br /&gt;
endif()&lt;br /&gt;
&lt;br /&gt;
set(CMAKE_CXX_FLAGS &amp;quot;-std=c++11 -fpermissive &amp;quot; ${MPI_COMPILE_FLAGS})&lt;br /&gt;
&lt;br /&gt;
set(SOURCE_EXE task1.cpp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
add_executable(task1 ${SOURCE_EXE})&lt;br /&gt;
&lt;br /&gt;
target_link_libraries(task1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запуск производился на вычислительных узлах суперкомпьютера &amp;quot;Ломоносов&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров [1 : 128] по степеням 2;&lt;br /&gt;
* размер матрицы [1000 : 10000] с шагом 1000.&lt;br /&gt;
&lt;br /&gt;
[[file:Blizntime.png|thumb|center|1000px|Рисунок 2. Время работы программы в зависимости от количества процессоров и размера матрицы]]&lt;br /&gt;
&lt;br /&gt;
Можно заметить, что при небольшом количестве входных данных, и большом количестве процессоров эффективность распараллеливания падает до нуля, поскольку время вычисления элементов вектора &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; становится несоизмеримо малым по сравнению с временем, затраченным на пересылку в пункте (3). &lt;br /&gt;
&lt;br /&gt;
[[file:Efficiency(paral).png|thumb|center|1000px|Рисунок 4. Эффективность распараллеливания в зависимости от количества процессоров и размера матрицы]]&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;
SciPy [https://docs.scipy.org/doc/scipy-0.18.1/reference/index.html],&lt;br /&gt;
&lt;br /&gt;
MatLab [https://www.mathworks.com/help/matlab/math/sparse-matrix-operations.html],&lt;br /&gt;
&lt;br /&gt;
Intel MKL [https://software.intel.com/en-us/articles/intel-math-kernel-library-inspector-executor-sparse-blas-routines].&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Blizn&amp;diff=19864</id>
		<title>Обсуждение участника:Blizn</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Blizn&amp;diff=19864"/>
		<updated>2016-12-01T23:53:30Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK) К Вашей работе есть несколько замечаний по содержанию.&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;- есть &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;- в каждой строке не превышает 10 в типичном случае;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;- ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
- Если первое определение подходит только для “теоретического анализа”, то чем лучше третье?&lt;br /&gt;
&lt;br /&gt;
- Второе определение, по-моему, не совсем корректно – оно слишком строгое, не понятно, что за типичный случай, почему именно используется привязка к строкам матрицы, почему именно 10 и т.д. Есть ли какие-то ссылки на литературу, где такое определение использовалось для анализа или для практических задач? Нужно пояснить смысл такого определения. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1.1.1 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В данном формате вместо одного двумерного массива, используются три одномерных.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Плотную матрицу можно представить и, например, в виде одномерного массива. Тогда получается обычный формат хранения лучше? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1.1.2 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Такие неупорядоченные представления могут быть очень удобны в практических вычислениях. Результаты большинства матричных операций получаются неупорядоченными, а их упорядочение стоило бы значительных затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы их представления были упорядоченными.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы привести примеры матричных операций, для которых неупорядоченное представление дает выигрыш, по сравнению с упорядоченным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.1.2 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Умножение разреженной матрицы на вектор используется и во многих других алгоритмах, методах и задачах, чем примечательны именно эти?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Достоинство этих процедур, по сравнению с какими? В некоторых итерационных методах, например, требуется также умножение и транспонированной матрицы на вектор.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.6 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для умножения разреженной матрицы общего вида, хранимой в форме &#039;&#039;&#039;RR(C)U&#039;&#039;&#039;, размером &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt; на заполненный вектор &amp;lt;math&amp;gt;m \times 1&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; сложений,&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; умножений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Что здесь понимается как «наиболее быстрый вариант»? Есть ли какие-то более медленные альтернативы? Оценка &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; сложений похоже не совсем правильная. Например, сколько нужно сложений для матрицы с одним ненулевым элементом в алгоритме 1.5?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.8 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Можно ли записать параллельный алгоритм, использующий больше чем n процессоров, где n - число строк(столбцов)?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 1.10 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Таким образом хранение в формате RR(C) не является эффективным для матриц, в которых &amp;lt;math&amp;gt;l &amp;gt; \frac{xnm - y(n+1)}{x+y}&amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно уточнить по какому критерию сравнивается «эффективность». Просто занимает меньше памяти? Или, например, сравнивается скорость доступа к памяти или время выполнения матричных операций?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пункт 2.4 ==&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:50, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно явно написать в тексте, что рассматривался целочисленный алгоритм. Почему не вещественное матрично-векторное умножение? Приводимые оценки для числа операций алгоритма (п.1.6, 1.8) разве учитывают вспомогательные целочисленные операции, например, для организации циклов?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;размер матрицы [1000 : 10000] с шагом 1000.&#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;
== Статья [[Участник:Blizn/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор.]] ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Отсутствующие части ===&lt;br /&gt;
* Нет информации в разделе 2.7. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 16:47, 27 октября 2016 (MSK)&lt;br /&gt;
* Не заполнен раздел 2.4 описания. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 15:27, 16 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
=== Замечания по тексту ===&lt;br /&gt;
* В разделе 1.4 не нужно дублировать написанное в разделе 1.3, а требуется описание алгоритма на верхнем уровне. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 16:47, 27 октября 2016 (MSK)&lt;br /&gt;
** Замечание не исправлено. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 16:04, 2 ноября 2016 (MSK)&lt;br /&gt;
* В разделе 2.4 не приведены все параметры запуска теста - какой компилятор, с какими опциями использовался, какие версии библиотек, на каких узлах проводился запуск и т.д. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 11:09, 30 ноября 2016 (MSK) &lt;br /&gt;
* В разделе 2.4 не приведён сам текст использованной в экспериментах реализации алгоритма. [[Участник:ASA|Александр Сергеевич Антонов]] ([[Обсуждение участника:ASA|обсуждение]]) 11:09, 30 ноября 2016 (MSK)&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lexaloris&amp;diff=19863</id>
		<title>Обсуждение участника:Lexaloris</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lexaloris&amp;diff=19863"/>
		<updated>2016-12-01T23:25:27Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основной вопрос. Ядро это все-таки умножение матрицы или строки матрицы? Соответственно под это нужно подстраивать и остальной текст, потому что можно понять и так, и так.&lt;br /&gt;
&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
К Вашей работе есть несколько замечаний по содержанию&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.1 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для умножения разреженной матрицы на вектор.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Минимальные требования к памяти, по отношению к любым другим способам хранения разреженных матриц даже специального вида? Нужно также пояснить в чем удобство именно этого подхода, по отношению к другим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.2 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Неупорядоченные представления могут быть очень удобны. Результаты большинства матричных операций получаются не­ упорядоченными, и упорядочение их стоило бы больших затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы представления были упорядоченными.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы привести примеры матричных операций, для которых неупорядоченное представление дает выигрыш, по сравнению с упорядоченным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Псевдокод и схема алгоритма написаны с ошибками и отличаются друг от друга. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
Нужно привести точное число операций для данного алгоритма и описать какие операции используются.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При классификации по высоте ЯПФ, алгоритм имеет линейную сложность. При классификации по высоте ЯПФ также линейную.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Дважды описывается сложность по высоте ЯПФ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#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;
= Пункт 2.4 =&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 14:17, 17 ноября 2016 (MSK) необходимо доработать:&lt;br /&gt;
&lt;br /&gt;
Требования были такие: &lt;br /&gt;
- Реализация: полностью собственная или обращение к библиотечной функции (Intel MKL, PETSc, FFTW, ScaLAPACK). В любом случае, текст исследуемой программы должен быть представлен в отчете. &lt;br /&gt;
- Компьютерная платформа может быть любой (Ломоносов, BlueGene или что-то иное). Описание компьютерной платформы должно быть в отчете. &lt;br /&gt;
- Должен быть представлен график сильной масштабируемости (зависимости производительности от числа процессов; если при этом&lt;br /&gt;
ещё и зависимость от размера задачи - это только в плюс). График должен выглядеть пристойно и понятно, оси и единицы измерения должны быть подписаны. К графику обязательно должны быть словесные пояснения! Требовалось подобрать такие размеры задачи и числа процессоров, чтобы отразить на графике характерные точки, описывающие свойства алгоритма и программы.&lt;br /&gt;
&lt;br /&gt;
[[Участник:Dan|Dan]] ([[Обсуждение участника:Dan|обсуждение]]) 11:00, 21 ноября 2016 (MSK) &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;
--[[Участник:Evgeny Mortikov|Evgeny Mortikov]] ([[Обсуждение участника:Evgeny Mortikov|обсуждение]]) 02:21, 2 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Параллельная реализация алгоритма позволяет до некоторой степени сократить время вычислений в несколько раз.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Почему в несколько раз, если на графике время счета уменьшается почти на порядок?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В разделе нужно пояснить, какая программная реализация использовалась в экспериментах с (RR (С) U) форматом, входит ли в расчет генерация матрицы, ее преобразование в разреженный формат, операции записи-чтения. Также нужно указать размерность и структуру матрицы в экспериментах и привести ссылку на описание кластера.&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=19783</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%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=19783"/>
		<updated>2016-12-01T00:18:50Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&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;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
Руфина Третьякова отвечает за программную реализацию алгоритма, Екатерина Буторина - за написание статьи.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ЧАСТЬ. Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&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;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф рассмотрим процесс вычисления значения одного элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Число последовательных ярусов равно числу последовательных операций -- &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; (в данном случае умножение и сложение будем считать за одну операцию).&lt;br /&gt;
Если же вычисления всех &amp;lt;math&amp;gt;y_i&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;
[[Файл:Pic.jpg|800x800px|center|thumb|Информационный граф алгоритма умножения разреженной матрицы на плотный вектор &lt;br /&gt;
(Рисунок составлен самостоятельно)]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Возможность параллельной реализации алгоритма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== ЧАСТЬ. Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Наитивная реализация алгоритма следующая: &lt;br /&gt;
# один процессор назначается управляющим&lt;br /&gt;
# управляющий процессор считывает или генерирует (если матрица задается известной формулой) матрицу в CSR формате &amp;lt;math&amp;gt; [ AI, AJ, A ] &amp;lt;/math&amp;gt;&lt;br /&gt;
# управляющий процессор считывает или генерирует вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt;&lt;br /&gt;
# управляющий процессор разделяет матрицу на блоки в зависимости от числа процессоров и рассылает остальным процессорам строки матрицы и вектор&lt;br /&gt;
# все процессоры вычисляют произведение своего блока матрицы на вектор&lt;br /&gt;
# управляющий процессор собирает результаты&lt;br /&gt;
Данный алгоритм несмотря на кажщуюся простоту оказывается весьма неэффективен, так как время пересылок оказывается на порядки больше времени вычисления. Более того, при большом количестве процессоров время выполнения параллельной программы оказывается больше времени выполнения последовательной программы. Производительность и эффективность работы данного алгоритма показаны на рисунках 1 и 2.&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt; &lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:perf_drto.png|thumb|none|800px|Рисунок 1: производительность умножения разреженной матрицы на вектор при считывании управляющим процессором (время считывания и пересылок учтено)]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:effc_drto.png|thumb|none|800px|Рисунок 2: эффективность умножения разреженной матрицы на вектор при считывании управляющим процессором (время считывания и пересылок учтено)]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&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;
Данный алгоритм отличается лучшим быстродействием (по крайней мере, время работы параллельной программы уменьшается с увеличением числа процессоров). Производительность и эффективность алгоритма можно увидеть на рисунках 3-6.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt; &lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:perf_drtc.png|thumb|none|800px|Рисунок 3: производительность умножения разреженной матрицы на вектор при параллельном считывании (время считывания и пересылок учтено)]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:effc_drtc.png|thumb|none|800px|Рисунок 4: эффективность умножения разреженной матрицы на вектор при параллельном считывании (время считывания и пересылок учтено)]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt; &lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:perf_clrc.png|thumb|none|800px|Рисунок 5: производительность умножения разреженной матрицы на вектор при параллельном считывании (учитывается только время вычислений)]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:effc_clrc.png|thumb|none|800px|Рисунок 6: эффективностьь умножения разреженной матрицы на вектор при параллельном считывании (учитывается только время вычислений)]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следует заметить, что в данной реализации матрица генерировалась при помощи случайных числел, и кроме того кластер, на котором прозиводились эксперименты не является однородным, различные ядра имеют различные характеристики, вследствие чего возникает &amp;quot;рельефность&amp;quot; производительности и эффективности.&lt;br /&gt;
&lt;br /&gt;
Если производить анализ алгоритма по суммарному времени работы программы (рис. 3,4), то эффективность уменьшается практически до нуля при увеличении числа процессоров, а производительность выше при малом числе процессоров и малом размере матрицы, за исключением нескольких &amp;quot;пиков&amp;quot; на средних размерах матрицы и большом числе процессоров. Если же анализировать непосредственно время вычислений, то производительность и эффективность оказываются значительно выше. На &amp;quot;пиках&amp;quot; наблюдается сверхлинейное ускорение (рис. 6), и в целом эффективность лучше для больших размеров матрицы. Производительность также имеет данные &amp;quot;пики&amp;quot;, и становится выше для больших размеров матрицы.&lt;br /&gt;
&lt;br /&gt;
Тестирование производилось на кластере cluster2 ИВМ РАН.&lt;br /&gt;
&#039;&#039;Я бы с удовольствием выполнила задание на Ломоносове или BlueGene, если бы мне дали доступ к ним!&#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;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=19782</id>
		<title>Обсуждение участницы:Trrufina</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=19782"/>
		<updated>2016-12-01T00:12:00Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Хорошая работа. Есть несколько замечаний&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это предложение нужно переформулировать. Разреженные матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
&#039;&#039;&#039;Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&#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;
&#039;&#039;&#039;Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет ли влиять выполнение свойства ассоциативности для сложения на детерминированность алгоритма? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
&lt;br /&gt;
Лучше использовать одинаковую индексацию для псевдокода алгоритма (1.4) и для схемы реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Оценка для числа сложений похоже не совсем правильная для алгоритма в 1.5 (например, для матрицы с одним ненулевым элементом).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
&lt;br /&gt;
Можно ли записать параллельный алгоритм, использующий больше чем n процессоров, где n - число строк(столбцов)?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.9 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В оценке не учитывается пункт 1 – размер разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
&lt;br /&gt;
Непонятно какая реализация алгоритма использовалась в экспериментах. Если это собственная реализация, то нужно кратко описать язык программирования, библиотеки, которые использовались и т.п. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. управляющий процессор разделяет матрицу на блоки в зависимости от числа процессоров и рассылает остальным процессорам строки матрицы и вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Разделение матрицы идет только по строкам или по блокам матрицы?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатка - &#039;&#039;&#039;Данный алгоритм несмотря на кажщуюся простоту&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нужно описать, что подразумевается под «Matrix size» на рисунках, число ненулевых элементов или размерность матрицы, и указать обе величины в численных экспериментах. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Улучшенный алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;4. управляющий (нулевой) процессор собирает результат или же каждый процессор записывает свою часть результата (при помощи процедур параллельной записи)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Если в расчет и 1-го алгоритма и «улучшенного алгоритма» входила параллельная запись в файл, а не просто сборка данных на управляющем процессоре, то нужно это явно уточнить в тексте.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатки - Следует заметить, что в данной реализации матрица генерировалась при помощи случайных &#039;&#039;&#039;числел&#039;&#039;&#039;, и кроме того кластер, на котором &#039;&#039;&#039;прозиводились&#039;&#039;&#039; эксперименты не является однородным, различные ядра имеют различные характеристики, вследствие чего возникает &amp;quot;рельефность&amp;quot; производительности и эффективности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Тестирование производилось на кластере cluster2 ИВМ РАН.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно добавить ссылку на описание кластера.&lt;br /&gt;
Почему не проводились эксперименты только на очередях из однородных ядер на кластере ИВМ?&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Janyell/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=19781</id>
		<title>Участник:Janyell/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Janyell/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=19781"/>
		<updated>2016-11-30T23:52:37Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(nz)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;nz + m&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;
&#039;&#039;&#039;Авторы описания:&#039;&#039;&#039; [[Участник:Janyell|Е.А. Сычева]] (разделы [[#Диагональная схема хранения ленточных матриц|1.1.1.1]], &lt;br /&gt;
[[#Профильная схема хранения симметричных матриц|1.1.1.2]],&lt;br /&gt;
[[#Умножение разреженной матрицы на вектор|1.1.2]],&lt;br /&gt;
[[#Математическое описание алгоритма|1.2]] - [[#Последовательная сложность алгоритма|1.6]],&lt;br /&gt;
[[#Входные и выходные данные алгоритма|1.9]],&lt;br /&gt;
[[#Свойства алгоритма|1.10]]) и [[Участник:ahahalin|А.С. Хахалин]] (разделы [[#Связные схемы разреженного хранения|1.1.1.3]] - [[#Хранение блочных матриц|1.1.1.6]],&lt;br /&gt;
[[#Информационный граф|1.7]],&lt;br /&gt;
[[#Ресурс параллелизма алгоритма|1.8]],&lt;br /&gt;
[[#Масштабируемость алгоритма и его реализации|2.4]],&lt;br /&gt;
[[#Существующие реализации алгоритма|2.7]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — матрица с большим количеством нулевых элементов.&lt;br /&gt;
&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разреженной. Матрицу порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; называют &#039;&#039;разреженной&#039;&#039;, если число ее ненулевых элементов &amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* есть &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Приве­денное определение полезно только для теоретических целей типа попытки оценить асимптотическое поведение алгоритма.&lt;br /&gt;
* ограничено в строке, в типичном случае от 2 до 10.&lt;br /&gt;
* выражается как &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
* таково, что для данной матрицы, данного алгоритма и данной вычислительной машины имеет смысл извлекать выгоду из на­личия в ней многих нулей.&lt;br /&gt;
&lt;br /&gt;
Всякую разреженную матрицу можно обрабатывать так, как если бы она была плотной: напротив, вся­кую плотную, или заполненную, матрицу можно обрабатывать алгоритмами для разреженных матриц. В обоих случаях полу­чатся правильные численные результаты, но вычислительные затраты возрастут. Приписывание матрице свойства разреженности эквивалентно утверждению о существовании алгоритма, исполь­зующего ее разреженность и делающего вычисления с ней дешевле по сравнению со стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Три основных идеи, которые направляли развитие большей части технологии разреженных матриц: &lt;br /&gt;
* &#039;&#039;&#039;хранить только ненулевые элементы&#039;&#039;&#039;. Разреженная матрица, будучи множеством чисел, не имеющим регулярности, не может быть представлена в памяти машины тем же простым способом, что и полная матрица - регулярным числовым массивом. Поэтому возникает необходимость дополнительно хранить индексную информацию, указывающую расположение каждого элемента в регулярном массиве.&lt;br /&gt;
* &#039;&#039;&#039;оперировать только с ненулевыми элементами&#039;&#039;&#039;. Число операций, производимых машиной при исполнении алгоритма, пропорционально числу ненулевых элементов, а не числу всех элементов матрицы.&lt;br /&gt;
* &#039;&#039;&#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;
Матрицу &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; называют &#039;&#039;ленточной&#039;&#039;, если все ее ненулевые элементы заключены внутри ленты, образованной диагоналями, параллельными главной диагонали. Таким образом, &amp;lt;math&amp;gt;a_{ij} = 0&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;|i - j| &amp;gt; b&amp;lt;/math&amp;gt;, и &amp;lt;math&amp;gt;a_{k, k-b} \ne 0&amp;lt;/math&amp;gt;, либо &amp;lt;math&amp;gt;a_{k, k+b} \ne 0&amp;lt;/math&amp;gt; хотя бы для одного значения &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;. Здесь &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — &#039;&#039;полуширина&#039;&#039;, а &amp;lt;math&amp;gt;2b + 1&amp;lt;/math&amp;gt; — &#039;&#039;ширина ленты&#039;&#039;. &#039;&#039;Лентой&#039;&#039; матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; называется множество элементов, для которых &amp;lt;math&amp;gt;|i - j| \leq b&amp;lt;/math&amp;gt;. Другими словами, для всякой строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; ленте принадлежат все элементы со столбцовыми индексами от &amp;lt;math&amp;gt;i - b&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;i + b&amp;lt;/math&amp;gt;, т. е. &amp;lt;math&amp;gt;2b + 1&amp;lt;/math&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
Если матрица симметрична, то достаточно хранить ее &#039;&#039;полу­ленту&#039;&#039;. Верхняя полулента состоит из элементов, находящихся в верхней части ленты, т. е. таких, что &amp;lt;math&amp;gt;0 &amp;lt; j - i \leq \beta &amp;lt;/math&amp;gt;; нижняя полулента состоит из элементов нижней части ленты, т. е. таких, что &amp;lt;math&amp;gt;0 &amp;lt; i - j \leq \beta&amp;lt;/math&amp;gt;; в обоих случаях в строке &amp;lt;math&amp;gt;\beta&amp;lt;/math&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
С ленточными матрицами связана простейшая и наиболее широко применяемая стратегия использования нулевых элементов матрицы. &#039;&#039;Диагональная схема&#039;&#039; хранения симметричной ленточной ма­трицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; и полуширины ленты  &amp;lt;math&amp;gt;\beta&amp;lt;/math&amp;gt; представляет собой массив &amp;lt;math&amp;gt;AN (I, J)&amp;lt;/math&amp;gt; размером &amp;lt;math&amp;gt;n \times (\beta + 1)&amp;lt;/math&amp;gt;. Главная диагональ хранится в последнем столбце, а нижние кодиагонали — в остальных столбцах со сдвигом на одну позицию вниз при каждом смещении влево. &lt;br /&gt;
&lt;br /&gt;
Для несимметричной матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; необходим массив размером &amp;lt;math&amp;gt;n \times(2\beta + 1)&amp;lt;/math&amp;gt;; нижняя полулента и главная&lt;br /&gt;
диагональ хранятся прежним образом, а верхние кодиагонали — в правой части массива со сдвигом на одну позицию вверх при каждом смещении вправо. Диагональная схема удобна, если &amp;lt;math&amp;gt;\beta &amp;lt;&amp;lt; n &amp;lt;/math&amp;gt;. Она является схемой прямого доступа в том смысле, что имеется простое взаимно однозначное соответствие между положением элемента в матрице &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и его положением в массиве: &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;&lt;br /&gt;
хранится компонентой &amp;lt;math&amp;gt;AN (i, j - i + \beta + 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Профильная схема хранения симметричных матриц ====&lt;br /&gt;
Ленточная матрица высокого порядка может иметь широкую ленту и большое число нулей внутри ее. Для такой матрицы диагональная схема может быть очень неэкономной. &#039;&#039;Профильная схема&#039;&#039; или &#039;&#039;схема переменной ленты&#039;&#039; является более эффективной схемой хранения симметричных матриц.&lt;br /&gt;
&lt;br /&gt;
Для каждой строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; симметричной матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; положим: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_{i} = i - j_{min} (i)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;j_{min} (i)&amp;lt;/math&amp;gt; — минимальный столбцовый индекс строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, для которого &amp;lt;math&amp;gt;a_{ij} \ne 0&amp;lt;/math&amp;gt;. Таким образом, первый ненулевой элемент строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; находится на &amp;lt;math&amp;gt;\beta_{i}&amp;lt;/math&amp;gt;- позиций левее главной диагонали.&lt;br /&gt;
&lt;br /&gt;
&#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;0 &amp;lt; i - j &amp;lt; \beta_{i}&amp;lt;/math&amp;gt; В строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; оболочке принадлежат все элементы со столбцовыми индексами от &amp;lt;math&amp;gt;j_{min} (i)&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;i - 1&amp;lt;/math&amp;gt;, всего &amp;lt;math&amp;gt;\beta_{i}&amp;lt;/math&amp;gt; элементов. Диагональные элементы не входят в оболочку. &#039;&#039;Про­филь&#039;&#039; матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; определяется как число элементов в оболочке:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;profile (A) = \sum\limits_{i}\beta_{i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При использовании профильной схемы все элементы оболочки, упорядоченные по строкам, хранятся, включая нули, в одномер­ном массиве &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Диагональный элемент данной строки помещается в ее конец. Длина массива &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; равна сумме профиля и порядка &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Кроме того, необходим массив указателей &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;; элементы этого массива - указатели расположения диагональ­ных элементов в &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;. Так, при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; элементы строки &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; находятся в позициях от &amp;lt;math&amp;gt;IA (i - 1) + 1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA (i)&amp;lt;/math&amp;gt;. Единственный элемент &amp;lt;math&amp;gt;a_{11}&amp;lt;/math&amp;gt; 1-й строки хранится в &amp;lt;math&amp;gt;AN (1)&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;
Рассмотрим разреженную матрицу &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Ее ненулевые элементы, которых очень мало в сравнении с числом нулей, рассеяны по всей матрице, образуя &#039;&#039;портрет&#039;&#039; матрицы или &#039;&#039;шаблон нулей—ненулей&#039;&#039;. Опишем схему хранения предложенную Кнутом. Ненулевые элементы хранятся в компактной форме и в произвольном порядке в одномерном массиве &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;.  Информация о положении элементов может храниться двумя дополнительными параллельными одномерными массивами &amp;lt;math&amp;gt;I&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt;; здесь для каждого ненулевого элемента содержатся его строчный и столбцовый индексы. Таким образом, для каждого &amp;lt;math&amp;gt;a_{ij}\ne0&amp;lt;/math&amp;gt; в памяти находится тройка &amp;lt;math&amp;gt;(a_{ij},i,j)&amp;lt;/math&amp;gt;. Далее, чтобы можно было легко отыскать элементы произвольной строки или столбца, необходимы ещё пара указателей для каждой тройки, а также &#039;&#039;указатели входа&#039;&#039; для &#039;&#039;строк&#039;&#039; и &#039;&#039;столбцов&#039;&#039;, сообщающие начало каждого строчного или столбцового списка. Пусть &amp;lt;math&amp;gt;NR&amp;lt;/math&amp;gt; (&amp;quot;next nonzero element in the same row&amp;quot; — &amp;quot;следующий ненулевой элемент той же строки&amp;quot;) — массив, хранящий строчные указатели, а &amp;lt;math&amp;gt;NC&amp;lt;/math&amp;gt; (&amp;quot;next nonzero element in the same column&amp;quot; — &amp;quot;следующий ненулевой элемент того же столбца&amp;quot;) — массив столбцовых указателей. Пять массивов &amp;lt;math&amp;gt;AN,I,J,NR,NC&amp;lt;/math&amp;gt; имеют общую длину, и их одноименные позиции соответствуют друг другу. Пусть &amp;lt;math&amp;gt;JR&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JC&amp;lt;/math&amp;gt; — массивы, содержащие указатели входа для строк и столбцов, расположенные в соответствии с порядком строк и столбцов матрицы. Тогда, например, для просмотра &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; строки необходимо:&lt;br /&gt;
# определить входной индекс &amp;lt;math&amp;gt;j=JR[i]&amp;lt;/math&amp;gt;&lt;br /&gt;
# определить элемент &amp;lt;math&amp;gt;AN[j]&amp;lt;/math&amp;gt;&lt;br /&gt;
# найти индекс следующего элемента &amp;lt;math&amp;gt;j=NR[j]&amp;lt;/math&amp;gt;&lt;br /&gt;
# если &amp;lt;math&amp;gt;j=0&amp;lt;/math&amp;gt;, то мы обошли все элемент &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки, иначе, перейти в п.2&lt;br /&gt;
Заметим, что рассмотренная схема требует пять ячеек памяти для каждого ненулевого элемента, а также 2 массива указателей входа для строк и столбцов. Вследствие большой накладной памяти такая схема весьма неэкономна. Достоинства её в том, что в любом месте можно включить или исключить элемент, а также можно эффективно сканировать строки и столбцы.&lt;br /&gt;
&lt;br /&gt;
==== Разреженный строчный формат ====&lt;br /&gt;
&lt;br /&gt;
Рассмотрим матрицу &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;(рис. 1). &lt;br /&gt;
&lt;br /&gt;
[[File:SuperSparseStoreAndMultiplyMatrix1.png|thumb|center|200px|Рисунок 1. Матрица A]]&lt;br /&gt;
&lt;br /&gt;
Значения ненулевых элементов и соответствующие столбцовые индексы хранятся в этой схеме по строкам в двух массивах — &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; соответственно. Дополнительно также используется массив указателей &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;, отмечающих позиции массивов &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;, с которых начинается описание очередной строки. Дополнительная компонента в &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; содержит указатель первой свободной позиции в &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. В общем случае описание &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;-й строки &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; хранится в позициях с &amp;lt;math&amp;gt;IA (r)&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA (r + 1) - 1&amp;lt;/math&amp;gt; массивов &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;, за исключением равенства &amp;lt;math&amp;gt;IA (r + 1) = IA (r)&amp;lt;/math&amp;gt;, означающего, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;-я строка пуста. Если матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; имеет &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; строк, то &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; содержит &amp;lt;math&amp;gt;m + 1&amp;lt;/math&amp;gt; позиций. [[File:SuperSparseStoreAndMultiplyRRCOFormat.png|thumb|right|300px|Рисунок 2. Формат RR (C) O на примере матрицы А(рис.1)]]&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют &#039;&#039;полным&#039;&#039;, поскольку представлена вся матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, и &#039;&#039;упорядоченным&#039;&#039;, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов. Таким образом, это строчное представление, полное и упорядоченное, или сокращенно &#039;&#039;&#039;RR (C) O&#039;&#039;&#039; (рис. 2). Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Ordered&amp;quot; (строчное представление, полное и упорядоченное).&lt;br /&gt;
&lt;br /&gt;
Схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разряженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямым, так и итерационными методами.&lt;br /&gt;
&lt;br /&gt;
==== Неупорядоченные представления ====&lt;br /&gt;
&lt;br /&gt;
Рассмотрим формат &#039;&#039;&#039;RR(C)U&#039;&#039;&#039; (рис. 3). Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Unordered&amp;quot; (строчное представление, полное, но неупорядоченное).&lt;br /&gt;
&lt;br /&gt;
Аналогично RR(C)O формат RR(C)U представлен тремя массивами — &amp;lt;math&amp;gt;AN,JA,IA&amp;lt;/math&amp;gt;, но элементы в массивах &amp;lt;math&amp;gt;AN,JA&amp;lt;/math&amp;gt; относящиеся к одной строке, могут идти в произвольном порядке.[[File:SuperSparseStoreAndMultiplyRRCUFormat.png|thumb|right|300px|Рисунок 3. Формат RR (C) U на примере матрицы А (рис.1)]]&lt;br /&gt;
&lt;br /&gt;
Формат RR(C)U вводится по следующим причинам. Представления разреженных матриц необязательно должны быть упорядочены в том смысле, что, хотя упорядоченность строк соблюдается, внутри каждой строки элементы исходных матриц могут храниться в произвольном порядке. Такие неупорядоченные представления могут быть весьма удобны в практических вычислениях. Результаты большинства матричных операций получаются неупорядоченными, а их упорядочение стоило бы значительных затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы их представления были упорядоченными.&lt;br /&gt;
&lt;br /&gt;
Ещё одним форматом неупорядоченного представления является &#039;&#039;&#039;RR (U) U&#039;&#039;&#039; (рис. 4). Сокращенное название формата RR (U) U происходит от английского словосочетания &amp;quot;Row - wise Representation, Upper, Unordered&amp;quot; (строчное представление, верхний треугольник, неупорядоченное).[[File:SuperSparseStoreAndMultiplyRRUUFormat.png|thumb|right|300px|Рисунок 4. Формат RR (U) U на примере матрицы А (рис.1)]]&lt;br /&gt;
&lt;br /&gt;
Данный формат используется для симметричных и верхних треугольных матриц, у которых большинство диагональных элементов отличны от нуля. В этом формате представляется только верхний треугольник матрицы (внутри каждой строки элементы могут храниться в произвольном порядке), а ее диагональные элементы хранятся в отдельном одномерном массиве. Верхняя треугольная матрица представляется  тремя массивами &amp;lt;math&amp;gt;AN,JA,IA&amp;lt;/math&amp;gt;, которые аналогичны массивам в формате RR(C)U.&lt;br /&gt;
&lt;br /&gt;
==== Хранение блочных матриц ====&lt;br /&gt;
&lt;br /&gt;
Идея разбиения большой матрицы на подматрицы или блоки возникает естественным образом. С блоками можно обращаться, как если бы они были элементами матрицы, и блочная матрица превращается в матрицу из матриц. Разбиение на блоки играет важную роль в технологии разреженных матриц, потому что многие алгоритмы, сконструированные первоначально для числовых матриц, можно обобщить на случай матриц из матриц. Большая гибкость, связанная с понятием разбиения, может давать определенные  вычислительные преимущества. С другой стороны, разбиение можно рассматривать просто как инструмент управления данными, помогающий организовать обмен информацией между оперативной памятью и внешними запоминающими устройствами. &lt;br /&gt;
&lt;br /&gt;
Хранение блочной матрицы подразумевает хранение множества её подматриц. Рассмотрим &#039;&#039;неявную схему хранения&#039;&#039;, предназначенную главным образом для симметричных матриц с квадратными диагональными блоками. Диагональные блоки рассматриваются так, как если бы они составляли единую матрицу, и хранятся в соответствие с [[#Профильная схема хранения симметричных матриц|профильной схемой]]. Численные значения элементов хранятся по строкам в массиве &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt;, а указатели на диагональные элементы каждой строки — в целом массиве &amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt;. Поддиагональные блоки рассматриваемые так, как если бы они составляли единую матрицу, хранятся посредством [[#Разреженный строчный формат|разреженного строчного формата]]. Ненулевые элементы размещаются по строкам в вещественном массиве  &amp;lt;math&amp;gt;AP&amp;lt;/math&amp;gt;, а соответствующие столбцовые индексы — в параллельном целом массиве &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Указатели начала строк хранятся в массиве &amp;lt;math&amp;gt;IP&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Умножение разреженной матрицы на вектор ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; используется при вычислении векторов Ланцоша, необходимом при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матрич­ная операция — это повторное умножение матрицы на последо­вательность заполненных векторов; сама матрица не меняется. Следовательно, наиболее релевантными для этих задач являются статические схемы хранения.&lt;br /&gt;
&lt;br /&gt;
В зависимости от формы представления матрицы используются различные алгоритмы. Далее рассмотрим простейший случай — это когда матрица, прямоугольная или квадратная, хранится в форме RR (С) U.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Исходные данные: разреженная матрица общего вида &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i = 1, \ldots, n&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j = 1, \ldots, m&amp;lt;/math&amp;gt;), заполненный вектор-столбец &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j = 1, \ldots, m&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: заполненный вектор-столбец &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i = 1, \ldots, n&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Формулы метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = 1}^{nz{_i}} a_{i,j=j(k)}b_{j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;nz{_i}&amp;lt;/math&amp;gt; - количество ненулевых элементов &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j = 1, \ldots, m&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;j = j(k)&amp;lt;/math&amp;gt; - индексная информация, указывающая расположение ненулевого элемента &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i = 1, \ldots, n&amp;lt;/math&amp;gt; и соответствующего элемента &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Существует также блочная версия метода, однако в данном описании разобран только точечный метод.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро умножения разреженной матрицы на вектор можно составить из множественных (всего их &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) вычислений скалярных произведений вектор-строк &amp;lt;math&amp;gt;a^i&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a^i_{k}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;k = 1, \ldots, nz_{i}&amp;lt;/math&amp;gt;), состоящих из ненулевых элементов &amp;lt;math&amp;gt;a_{i, j=j(k)}&amp;lt;/math&amp;gt;, на вектор-столбцы &amp;lt;math&amp;gt;b^i&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b^i_{k}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;k = 1, \ldots, nz_{i}&amp;lt;/math&amp;gt;), состоящих из элементов &amp;lt;math&amp;gt;b_{j=j(k)}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i = 1, \ldots, n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum\limits_{k = 1}^{nz_{i}} a^i_k b^i_k&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;
Как записано и в [[#Вычислительное ядро алгоритма|описании ядра алгоритма]], основную часть метода составляют множественные (всего &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) вычисления сумм:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum\limits_{k = 1}^{nz_{i}} a^i_k b^i_k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
в режиме накопления или без него.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Последовательность исполнения метода следующая:&lt;br /&gt;
&lt;br /&gt;
Далее описывается простейший случай — матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; хранится в форме RR (С) U.&lt;br /&gt;
&lt;br /&gt;
1. &amp;lt;math&amp;gt;k^0_{nz} = IA(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Далее для всех &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; по нарастанию выполняются&lt;br /&gt;
&lt;br /&gt;
2. &amp;lt;math&amp;gt;c_i = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. &amp;lt;math&amp;gt;k^i_0 = k^{i - 1}_{nz}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. &amp;lt;math&amp;gt;k^i_{nz} = IA(i + 1) - 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. &amp;lt;math&amp;gt;c_{i} = \sum\limits_{k = k^i_0}^{k^i_{nz}} AN(k) b_{JA(k)}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого (если &amp;lt;math&amp;gt;i \le n&amp;lt;/math&amp;gt;) происходит переход к шагу 2 с бо́льшим &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Особо отметим, что вычисления &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt; производят в режиме накопления сложением произведений &amp;lt;math&amp;gt;AN(k) b_{JA(k)}&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;k^i_0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k^i_{nz}&amp;lt;/math&amp;gt;, c нарастанием &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для алгоритма умножения разреженной матрицы размером &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;, представленной в формате RR (C) U, на вектор длины &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; сложений (вычитаний),&lt;br /&gt;
* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; умножений,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; - количество ненулевых элементов матрицы &amp;lt;math&amp;gt;A&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;
При классификации по последовательной сложности, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам со сложностью &amp;lt;math&amp;gt;O(nz)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Опишем [[глоссарий#Граф алгоритма|граф алгоритма]]&amp;lt;ref&amp;gt;Воеводин В.В.  Математические основы параллельных вычислений// М.: Изд. Моск. ун-та, 1991. 345 с.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002. – 608 с.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Фролов А.В.. Принципы построения и описание языка Сигма. Препринт ОВМ АН N 236. М.: ОВМ АН СССР, 1989.&amp;lt;/ref&amp;gt; как аналитически, так и в виде рисунка. Далее предполагается, что матрица &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; представлена в формате RR (C) U.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция  &amp;lt;math&amp;gt;a*b&amp;lt;/math&amp;gt;.  Естественно введённые координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от 1 до &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, принимая все целочисленные значения; &lt;br /&gt;
*&amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;— меняется в диапазоне от 1 до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; зависит от &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; и соответствует числу ненулевых элементов в &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ой строке матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, которое равно &amp;lt;math&amp;gt;IA[j+1] - IA[j]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; — элемент массива &amp;lt;math&amp;gt;AN&amp;lt;/math&amp;gt; с индексом &amp;lt;math&amp;gt;IA_{j} + i&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — элемент входного вектора &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; с индексом &amp;lt;math&amp;gt;JA[IA_{j} + i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция  &amp;lt;math&amp;gt;a+b&amp;lt;/math&amp;gt;.  Естественно введённые координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от 3 до &amp;lt;math&amp;gt;k+1&amp;lt;/math&amp;gt;, принимая все целочисленные значения; &lt;br /&gt;
*&amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;— меняется в диапазоне от 1 до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; зависит от &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; и соответствует числу ненулевых элементов в &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ой строке матрицы &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, которое равно &amp;lt;math&amp;gt;IA[j+1] - IA[j]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;:&lt;br /&gt;
** при &amp;lt;math&amp;gt;i=3&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из первой группы, с координатами &amp;lt;math&amp;gt;i - 2, j&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i&amp;gt;3&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из второй группы, с координатами &amp;lt;math&amp;gt;i - 1, j&amp;lt;/math&amp;gt;;&lt;br /&gt;
*&amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из первой группы, с координатами &amp;lt;math&amp;gt;i - 1, j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;промежуточным данным&#039;&#039; алгоритма.&lt;br /&gt;
&lt;br /&gt;
Описанный граф можно посмотреть на рис. 5. Граф отображает параллельную версию произведения разреженной матрицы на вектор, где каждая строка показывает ядро алгоритма (произведение строки на вектор). Вершины, соответствующие входным и выходным данным обозначены прямоугольниками, а вершины, соответствующие операциям — окружностями. Здесь вершины первой группы обозначены зеленым цветом и буквосочетанием multi, вершины второй — синим цветом и знаком сложения.&lt;br /&gt;
&lt;br /&gt;
[[file:SuperSparseStoreAndMultiply_RRCU.png|thumb|center|1200px|Рисунок 5. Граф алгоритма. multi — произведение.]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для алгоритма умножения разреженной матрицы размером &amp;lt;math&amp;gt;n\times m&amp;lt;/math&amp;gt;, представленной в формате RR (C) U, на вектор длины &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* по &amp;lt;math&amp;gt;nz_{\max}&amp;lt;/math&amp;gt; ярусов умножений и сложений (в каждом из ярусов — &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций),&lt;br /&gt;
где &amp;lt;math&amp;gt;nz_{\max} = \max_{1 \leq i \leq n} nz_i \leq m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При этом использование режима накопления требует совершения умножений и сложений в режиме двойной точности, а в параллельном варианте это означает, что практически все промежуточные вычисления для выполнения алгоритма в режиме накопления должны быть двойной точности. В отличие от последовательного варианта это означает некоторое увеличение требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по высоте ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* разреженная матрица общего вида &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;a_{ij}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i = 1, \ldots, n&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j = 1, \ldots, m&amp;lt;/math&amp;gt;), заданная в формате RR (C) U;&lt;br /&gt;
&lt;br /&gt;
* заполненный вектор-столбец &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;b_{j}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;j = 1, \ldots, m&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; (без учета индексной информации, составляющей накладные расходы - массивы &amp;lt;math&amp;gt;JA, IA&amp;lt;/math&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; заполненный вектор-столбец &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i = 1, \ldots, n&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;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов равно &amp;lt;math&amp;gt;O(\frac{nz}{n})&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;
= Программная реализация алгоритма =&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;
Проведём исследование масштабируемости параллельной реализации умножения разреженной матрицы в формате RR(C)U на вектор. Исследование проводилось на [http://hpc.cmc.msu.ru/bgp вычислительном комплексе IBM Blue Gene/P]&amp;lt;ref&amp;gt;Вычислительный комплекс IBM Blue Gene/P http://hpc.cmc.msu.ru/bgp&amp;lt;/ref&amp;gt;. В качестве программной реализации была использована модифицированная версия [https://github.com/taoito/matvec-mpi программы]&amp;lt;ref&amp;gt;Thao Nguyen A sparse matrix-vector parallel multiplication implementation using MPI&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1, 10, 25, 50, 100]&lt;br /&gt;
*	количество ненулеввых элементов в матрице [1500, 40000, 150000, 600000, 3750000].&lt;br /&gt;
&lt;br /&gt;
На следующем рисунке приведен график времени выполнения выбранной реализации умножение разреженной матрицы в формате RR(C)U на вектор в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
[[file:RRCOMultiplaction Graphic.png|thumb|center|700px|Рисунок 6. Параллельная реализация умножение разреженной матрицы в формате RR(C)U на вектор.]]&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;
Алгоритм умножения разреженной матрицы на вектор входит в состав таких библиотек для вычислений с разреженными матрицами, как: SparseLib++[http://math.nist.gov/sparselib++/], uBLAS [http://www.boost.org/doc/libs/1_62_0/libs/numeric/ublas/doc/], Intel MKL [https://software.intel.com/en-us/intel-mkl], cuSPARSE [http://docs.nvidia.com/cuda/cusparse/] и др.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Janyell&amp;diff=19780</id>
		<title>Обсуждение участника:Janyell</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Janyell&amp;diff=19780"/>
		<updated>2016-11-30T23:51:11Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Добрый день. Подключаюсь к проверке. Статья мне в целом понравилась, и тем больше от этого хочется добавить замечаний, чтобы довести ее до того вида, чтобы она могла остаться на Алговики.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Уважаемые авторы, к Вашей работе есть новые замечания - они для удобства отделены горизонтальной линией от прошлых.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 = &lt;br /&gt;
Разреженная матрица, будучи множеством чисел, не имеющим регулярности, &#039;&#039;&#039;не может быть представлена в памяти машины тем же простым способом, что и полная матрица&#039;&#039;&#039;. Поэтому возникает необходимость дополнительно хранить индексную информацию, указывающую расположение каждого элемента в регулярном массиве.&lt;br /&gt;
&lt;br /&gt;
Что означает фраза, выделенная жирным? Или как-то переформулируйте утверждение, оно не понятно&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Однако многие схемы хранения допускают определенную долю нулей, и алгоритм обрабатывает их, как если бы они не были нулями.&#039;&#039;&#039;&lt;br /&gt;
Тоже непонятно&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица — матрица с большим количеством нулевых элементов.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Все же матрица с большим количеством нулей может быть сильно плотной и так лучше не писать.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* есть &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Приве­денное определение полезно только для теоретических целей типа попытки оценить асимптотическое поведение алгоритма.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* ограничено в строке, в типичном случае от 2 до 10.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* выражается как &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
- Если первое определение подходит только для “теоретического анализа”, то чем лучше третье?&lt;br /&gt;
&lt;br /&gt;
- Второе определение, по-моему, не совсем корректно – оно слишком строгое, не понятно, что за типичный случай, почему именно используется привязка к строкам матрицы, почему именно 2 и 10 (а, например, 1?) и т.д. Есть ли какие-то ссылки на литературу, где такое определение использовалось для анализа или для практических задач? Нужно пояснить смысл такого определения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Всякую разреженную матрицу можно обрабатывать так, как если бы она была плотной: напротив, вся­кую плотную, или заполненную, матрицу можно обрабатывать алгоритмами для разреженных матриц.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как можно обрабатывать плотную матрицу алгоритмами для разреженных матриц, если ее нужно представить в специальном виде?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* сохранять разреженность. Хоро­ший алгоритм для разреженных матриц пытается сохранить раз­реженность, по возможности уменьшая заполнение.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это свойство нужно пояснить. Не во всех задачах можно или желательно уменьшать заполнение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В целях упрощения операций с разреженными матрицами многие алгоритмы разрешают также хранить небольшое количество нулевых элементов и оперировать с ними как с ненулевыми.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Почему именно небольшое количество нулевых элементов?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.1 = &lt;br /&gt;
Поставьте определение ленточной матрицы в начало. Потому что, начиная читать первую фразу, сначала задаешься вопросом, что это такое&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.2 = &lt;br /&gt;
&#039;&#039;&#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;
&lt;br /&gt;
= Пункт 1.1.1.5 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Такие неупорядоченные представления могут быть весьма удобны в практических вычислениях. Результаты большинства матричных операций получаются неупорядоченными, а их упорядочение стоило бы значительных затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы их представления были упорядоченными.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы привести несколько примеров операций, для которых неупорядоченные представления дают выигрыш.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Данный формат используется для симметричных и верхних треугольных матриц, у которых большинство диагональных элементов отличны от нуля.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В чем здесь причина требования «большинство диагональных элементов отличны от нуля»? Формат предназначен для только симметричных или только верхних треугольных? Или и для тех и других?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.6 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Идея разбиения большой матрицы на подматрицы или блоки возникает естественным образом. С блоками можно обращаться, как если бы они были элементами матрицы, и блочная матрица превращается в матрицу из матриц.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это не так, поскольку матричные произведения необязательно коммутативны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разбиение на блоки играет важную роль в технологии разреженных матриц, потому что многие алгоритмы, сконструированные первоначально для числовых матриц, можно обобщить на случай матриц из матриц. Большая гибкость, связанная с понятием разбиения, может давать определенные  вычислительные преимущества.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы пояснить какие вычислительные преимущества это дает.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;С другой стороны, разбиение можно рассматривать просто как инструмент управления данными, помогающий организовать обмен информацией между оперативной памятью и внешними запоминающими устройствами. &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно подробнее пояснить какие преимущества блочное разбиение дает при организации обменов информации между оперативной памятью и внешними запоминающими устройствами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Рассмотрим &#039;&#039;неявную схему хранения&#039;&#039;, предназначенную главным образом для симметричных матриц с квадратными диагональными блоками.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В чем заключается неявность в такой схеме хранения?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.2 = &lt;br /&gt;
&#039;&#039;&#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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор используется при вычислении векторов Ланцоша, необходимом при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Умножение разреженной матрицы на вектор используется и во многих других алгоритмах, методах и задачах, чем примечательны именно эти?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матрич­ная операция — это повторное умножение матрицы на последо­вательность заполненных векторов; сама матрица не меняется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Достоинство этих процедур, по сравнению с какими? В некоторых итерационных методах, например, требуется также умножение и транспонированной матрицы на вектор. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Следовательно, наиболее релевантными для этих задач являются статические схемы хранения.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Есть ли такие схемы хранения, которые при выполнении матрично-векторного произведения изменяют матрицу или требуют изменения структуры данных?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 = &lt;br /&gt;
Почему вычислительное ядро только последовательной версии?&lt;br /&gt;
Вычислительное ядро (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.4 = &lt;br /&gt;
Наверное, вопрос в том, что алгоритм делает помимо запуска вычислительных ядер?&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Присвоение элементам заполненного вектора-столбца &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; результатов запуска вычислительных ядер.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 = &lt;br /&gt;
Как была выбрана форма хранения матрицы? Это нужно прокомментировать&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Комментарий был ранее, в пункте 1.1.2. Продублировали&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для алгоритма умножения разреженной матрицы размером &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;, представленной в формате RR (C) U, на вектор длины &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; сложений (вычитаний),&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; умножений,&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь понимается как «наиболее быстрый вариант»? Есть ли какие-то более медленные альтернативы? Оценка &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; сложений похоже не совсем правильная. Например, сколько нужно сложений для матрицы с одним ненулевым элементом в алгоритме 1.5? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При этом использование режима накопления требует совершения умножений и вычитаний в режиме двойной точности, что ещё больше увеличивает долю умножений и сложений/вычитаний во времени, требуемом для выполнения умножения разреженной матрицы на вектор.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Непонятное предложение. Увеличивается и доля сложений и доля умножений? Что меняется, с точки зрения числа операций, если делать расчет с двойной точностью?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 = &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.8 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При классификации по высоте ЯПФ, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по высоте ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Два раза повторяется сложность при классификации по высоте ЯПФ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 = &lt;br /&gt;
Пока пустой?&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Помимо ненулевых элементов нужно указать размерность матрицы и описать матрицу (случайная или нет, если нет, то какая), которая использовалась в экспериментах. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Это объясняется быстрым ростом накладных расходов на организацию параллельного выполнения. Это подтверждает предположение о том, что накладные расходы начинают сильно превалировать над вычислениями.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы поподробнее описать с чем связаны накладные расходы – обращением к файловой системе или межпроцессорными коммуникациями и какого вида.&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Janyell&amp;diff=19779</id>
		<title>Обсуждение участника:Janyell</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Janyell&amp;diff=19779"/>
		<updated>2016-11-30T23:40:37Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Добрый день. Подключаюсь к проверке. Статья мне в целом понравилась, и тем больше от этого хочется добавить замечаний, чтобы довести ее до того вида, чтобы она могла остаться на Алговики.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 = &lt;br /&gt;
Разреженная матрица, будучи множеством чисел, не имеющим регулярности, &#039;&#039;&#039;не может быть представлена в памяти машины тем же простым способом, что и полная матрица&#039;&#039;&#039;. Поэтому возникает необходимость дополнительно хранить индексную информацию, указывающую расположение каждого элемента в регулярном массиве.&lt;br /&gt;
&lt;br /&gt;
Что означает фраза, выделенная жирным? Или как-то переформулируйте утверждение, оно не понятно&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Однако многие схемы хранения допускают определенную долю нулей, и алгоритм обрабатывает их, как если бы они не были нулями.&#039;&#039;&#039;&lt;br /&gt;
Тоже непонятно&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица — матрица с большим количеством нулевых элементов.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Все же матрица с большим количеством нулей может быть сильно плотной и так лучше не писать.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* есть &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Приве­денное определение полезно только для теоретических целей типа попытки оценить асимптотическое поведение алгоритма.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* ограничено в строке, в типичном случае от 2 до 10.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* выражается как &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
- Если первое определение подходит только для “теоретического анализа”, то чем лучше третье?&lt;br /&gt;
&lt;br /&gt;
- Второе определение, по-моему, не совсем корректно – оно слишком строгое, не понятно, что за типичный случай, почему именно используется привязка к строкам матрицы, почему именно 2 и 10 (а, например, 1?) и т.д. Есть ли какие-то ссылки на литературу, где такое определение использовалось для анализа или для практических задач? Нужно пояснить смысл такого определения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Всякую разреженную матрицу можно обрабатывать так, как если бы она была плотной: напротив, вся­кую плотную, или заполненную, матрицу можно обрабатывать алгоритмами для разреженных матриц.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как можно обрабатывать плотную матрицу алгоритмами для разреженных матриц, если ее нужно представить в специальном виде?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* сохранять разреженность. Хоро­ший алгоритм для разреженных матриц пытается сохранить раз­реженность, по возможности уменьшая заполнение.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это свойство нужно пояснить. Не во всех задачах можно или желательно уменьшать заполнение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В целях упрощения операций с разреженными матрицами многие алгоритмы разрешают также хранить небольшое количество нулевых элементов и оперировать с ними как с ненулевыми.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Почему именно небольшое количество нулевых элементов?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.1 = &lt;br /&gt;
Поставьте определение ленточной матрицы в начало. Потому что, начиная читать первую фразу, сначала задаешься вопросом, что это такое&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.2 = &lt;br /&gt;
&#039;&#039;&#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;
&lt;br /&gt;
= Пункт 1.1.1.5 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Такие неупорядоченные представления могут быть весьма удобны в практических вычислениях. Результаты большинства матричных операций получаются неупорядоченными, а их упорядочение стоило бы значительных затрат машинного времени. В то же время, за немногими исключениями, алгоритмы для разреженных матриц не требуют, чтобы их представления были упорядоченными.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы привести несколько примеров операций, для которых неупорядоченные представления дают выигрыш.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Данный формат используется для симметричных и верхних треугольных матриц, у которых большинство диагональных элементов отличны от нуля.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В чем здесь причина требования «большинство диагональных элементов отличны от нуля»? Формат предназначен для только симметричных или только верхних треугольных? Или и для тех и других?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.6 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Идея разбиения большой матрицы на подматрицы или блоки возникает естественным образом. С блоками можно обращаться, как если бы они были элементами матрицы, и блочная матрица превращается в матрицу из матриц.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это не так, поскольку матричные произведения необязательно коммутативны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разбиение на блоки играет важную роль в технологии разреженных матриц, потому что многие алгоритмы, сконструированные первоначально для числовых матриц, можно обобщить на случай матриц из матриц. Большая гибкость, связанная с понятием разбиения, может давать определенные  вычислительные преимущества.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы пояснить какие вычислительные преимущества это дает.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;С другой стороны, разбиение можно рассматривать просто как инструмент управления данными, помогающий организовать обмен информацией между оперативной памятью и внешними запоминающими устройствами. &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно подробнее пояснить какие преимущества блочное разбиение дает при организации обменов информации между оперативной памятью и внешними запоминающими устройствами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Рассмотрим &#039;&#039;неявную схему хранения&#039;&#039;, предназначенную главным образом для симметричных матриц с квадратными диагональными блоками.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В чем заключается неявность в такой схеме хранения?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.2 = &lt;br /&gt;
&#039;&#039;&#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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор используется при вычислении векторов Ланцоша, необходимом при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Умножение разреженной матрицы на вектор используется и во многих других алгоритмах, методах и задачах, чем примечательны именно эти?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матрич­ная операция — это повторное умножение матрицы на последо­вательность заполненных векторов; сама матрица не меняется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Достоинство этих процедур, по сравнению с какими? В некоторых итерационных методах, например, требуется также умножение и транспонированной матрицы на вектор. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Следовательно, наиболее релевантными для этих задач являются статические схемы хранения.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Есть ли такие схемы хранения, которые при выполнении матрично-векторного произведения изменяют матрицу или требуют изменения структуры данных?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 = &lt;br /&gt;
Почему вычислительное ядро только последовательной версии?&lt;br /&gt;
Вычислительное ядро (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.4 = &lt;br /&gt;
Наверное, вопрос в том, что алгоритм делает помимо запуска вычислительных ядер?&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Присвоение элементам заполненного вектора-столбца &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; результатов запуска вычислительных ядер.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 = &lt;br /&gt;
Как была выбрана форма хранения матрицы? Это нужно прокомментировать&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Комментарий был ранее, в пункте 1.1.2. Продублировали&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для алгоритма умножения разреженной матрицы размером &amp;lt;math&amp;gt;n \times m&amp;lt;/math&amp;gt;, представленной в формате RR (C) U, на вектор длины &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; сложений (вычитаний),&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; умножений,&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь понимается как «наиболее быстрый вариант»? Есть ли какие-то более медленные альтернативы? Оценка &amp;lt;math&amp;gt;nz&amp;lt;/math&amp;gt; сложений похоже не совсем правильная. Например, сколько нужно сложений для матрицы с одним ненулевым элементом в алгоритме 1.5? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При этом использование режима накопления требует совершения умножений и вычитаний в режиме двойной точности, что ещё больше увеличивает долю умножений и сложений/вычитаний во времени, требуемом для выполнения умножения разреженной матрицы на вектор.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Непонятное предложение. Увеличивается и доля сложений и доля умножений? Что меняется, с точки зрения числа операций, если делать расчет с двойной точностью?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 = &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.8 = &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При классификации по высоте ЯПФ, таким образом, алгоритм умножения разреженной матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по высоте ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Два раза повторяется сложность при классификации по высоте ЯПФ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 = &lt;br /&gt;
Пока пустой?&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Помимо ненулевых элементов нужно указать размерность матрицы и описать матрицу (случайная или нет, если нет, то какая), которая использовалась в экспериментах. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Это объясняется быстрым ростом накладных расходов на организацию параллельного выполнения. Это подтверждает предположение о том, что накладные расходы начинают сильно превалировать над вычислениями.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Хорошо бы поподробнее описать с чем связаны накладные расходы – обращением к файловой системе или межпроцессорными коммуникациями и какого вида.&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Janyell&amp;diff=19773</id>
		<title>Обсуждение участника:Janyell</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Janyell&amp;diff=19773"/>
		<updated>2016-11-30T22:45:15Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Добрый день. Подключаюсь к проверке. Статья мне в целом понравилась, и тем больше от этого хочется добавить замечаний, чтобы довести ее до того вида, чтобы она могла остаться на Алговики.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 = &lt;br /&gt;
Разреженная матрица, будучи множеством чисел, не имеющим регулярности, &#039;&#039;&#039;не может быть представлена в памяти машины тем же простым способом, что и полная матрица&#039;&#039;&#039;. Поэтому возникает необходимость дополнительно хранить индексную информацию, указывающую расположение каждого элемента в регулярном массиве.&lt;br /&gt;
&lt;br /&gt;
Что означает фраза, выделенная жирным? Или как-то переформулируйте утверждение, оно не понятно&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Однако многие схемы хранения допускают определенную долю нулей, и алгоритм обрабатывает их, как если бы они не были нулями.&#039;&#039;&#039;&lt;br /&gt;
Тоже непонятно&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.1 = &lt;br /&gt;
Поставьте определение ленточной матрицы в начало. Потому что, начиная читать первую фразу, сначала задаешься вопросом, что это такое&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1.1.2 = &lt;br /&gt;
&#039;&#039;&#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;
= Пункт 1.1.2 = &lt;br /&gt;
&#039;&#039;&#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;
= Пункт 1.3 = &lt;br /&gt;
Почему вычислительное ядро только последовательной версии?&lt;br /&gt;
Вычислительное ядро (computational kernel) алгоритма - это часть алгоритма, на которую приходится основное время его работы.&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.4 = &lt;br /&gt;
Наверное, вопрос в том, что алгоритм делает помимо запуска вычислительных ядер?&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Присвоение элементам заполненного вектора-столбца &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; результатов запуска вычислительных ядер.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 = &lt;br /&gt;
Как была выбрана форма хранения матрицы? Это нужно прокомментировать&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Комментарий был ранее, в пункте 1.1.2. Продублировали&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 = &lt;br /&gt;
Правильно я понимаю, что на рисунке изображено вычисление всего произведения матрицы на вектор? Аналогичные блоки для разных строк. А разве не должен быть рисунок, изображающий ядро (то есть произведение одной строки на вектор)? &lt;br /&gt;
(я не уверен, поэтому спрашиваю. Возможно, это как-то надо лучше подписать)&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Нам показалось верным отобразить на рисунке именно параллельную версию, на которой будет видно как и произведение одной строки на вектор, так и вычисление всех элементов. Как следует из определения [[глоссарий#Граф алгоритма|графа алгоритма]], он должен давать удобное представление не только ядра, но и позволять рассмотреть алгоритм с параллельной точки зрения.  Внесли небольшое пояснение для рисунка.&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 = &lt;br /&gt;
Пока пустой?&lt;br /&gt;
&lt;br /&gt;
__&lt;br /&gt;
&lt;br /&gt;
Поправили&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=19772</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%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=19772"/>
		<updated>2016-11-30T22:36:38Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-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;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&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;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&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;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации умножения разреженной матрицы на вектор. Исследование проводилось на вычислительном комплексе [http://hpc.cmc.msu.ru/bgp Blue Gene/P]&amp;lt;ref&amp;gt; Blue Gene/P http://hpc.cmc.msu.ru/bgp&amp;lt;/ref&amp;gt;. Вычисления проводились с помощью следующего программного [https://www.dropbox.com/s/gx0s5r0jg58y8wa/main.c кода]&amp;lt;ref&amp;gt;Sparse matrix-vector MPI multiplication &amp;lt;/ref&amp;gt;. &lt;br /&gt;
Матрицы генерировались случайным образом.&lt;br /&gt;
&lt;br /&gt;
На следующем рисунке показана зависимость времени выполнения алгоритма от числа используемых процессоров и количества ненулевых элементов матрицы. Можно заметить, что скорость вычисления при переходе с последовательной на параллельную версию возросла значительно. Однако, дальнейшее увеличение числа вычислительных устройств не дает сильного прироста производительности. Это объясняется быстрым ростом накладных расходов на организацию параллельного выполнения.&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_more_points.png|thumb|center|1000px|Рис.3 Умножение разреженной матрицы на вектор. Масштабируемость]]&lt;br /&gt;
&lt;br /&gt;
На рисунке ниже изображен график эффективности в зависимости от числа процессоров и размера задачи. Можно заметить небольшой всплеск эффективности при использовании 64 процессоров.&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_eff_new.png|thumb|center|1000px|Рис.4 Умножение разреженной матрицы на вектор. Эффективность]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9&amp;diff=19771</id>
		<title>Обсуждение участника:Сергей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9&amp;diff=19771"/>
		<updated>2016-11-30T22:34:58Z</updated>

		<summary type="html">&lt;p&gt;Evgeny Mortikov: /* Правки */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Хорошая работа, но есть несколько замечаний.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;~ в каждой строке не превышает 10 в типичном случае;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
- Если первое определение подходит только для “теоретического анализа”, то чем лучше третье?&lt;br /&gt;
&lt;br /&gt;
- Второе определение, по-моему, не совсем корректно – оно слишком строгое, не понятно, что за типичный случай, почему именно используется привязка к строкам матрицы, почему именно 10 и т.д. Есть ли какие-то ссылки на литературу, где такое определение использовалось для анализа или для практических задач? Нужно пояснить смысл такого определения. &lt;br /&gt;
&lt;br /&gt;
- В силу того, что определить разреженную матрицу строго не получается, то можно упомянуть то, что разреженными матрицами можно считать именно те, для которых применение специализированных алгоритмов обработки и/или хранения является оправданным (см., например, короткое обсуждение в Gilbert et al., Sparse Matrices in MATLAB: Design and Implementation, 1992)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это предложение нужно переформулировать. Разреженные матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Что здесь понимается под эффективностью доступа к строкам матрицы и тем, что доступ к столбцам затруднен? Если речь идет об устройстве компьютерной памяти, то это нужно пояснить, поскольку до этого в разделе описывается просто структура данных.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Из этого определения можно получить матрицу со всеми ненулевыми элементами при &amp;lt;math&amp;gt;N \gg M&amp;lt;/math&amp;gt;, тогда &amp;lt;math&amp;gt;N M \ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.3 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Оценка для операций сложения здесь не до конца правильная (например, если матрица нулевая). Лучше оценку записать в форме равенства. Или вообще не рассматривать случай нулевых строк.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
См. пункт 1.3&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Почему &amp;lt;math&amp;gt;NZ + x = 2NZ?&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.9 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
См. пункт 1.2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.10 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Данный алгоритм обладает свойством детерминированности.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет ли влиять выполнение свойства ассоциативности для сложения на детерминированность алгоритма? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
&lt;br /&gt;
Включает ли численный эксперимент генерацию матрицы? Нужно также указать размерность самой матрицы, помимо числа ненулевых элементов.  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Можно заметить небольшой всплеск эффективности при использовании 64 процессоров.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
С чем связан этот «всплеск»? С алгоритмом, программой или вычислительной системой?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.7 =&lt;br /&gt;
&lt;br /&gt;
опечатка - &#039;&#039;&#039;... также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Evgeny Mortikov</name></author>
	</entry>
</feed>