<?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=Blizn</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=Blizn"/>
	<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/Blizn"/>
	<updated>2026-10-22T17:17:49Z</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: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=19883</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=19883"/>
		<updated>2016-12-02T14:02:58Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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>Blizn</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=19882</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=19882"/>
		<updated>2016-12-02T13:57:38Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Пункт 1.6 */&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;
&#039;&#039;&#039;В качестве теоретической основы использовался Писсанецки, ссылка на него указана выше в статье. Текст использовался именно оттуда, ничего своего я не придумывала. Почему именно 10? Потому что, как было сказано, НЕЛЬЗЯ дать строгого определения тому, начиная с какого количества элементов матрица перестаёт быть плотной и начинает считаться разреженной. А значит, что нельзя сказать, что запрещено определить матрицу именно так. По этой же причине ни одно определение не хуже и не лучше, они просто даны разными людьми в попытках дать более строгое определение, чем просто &amp;quot;много нулей&amp;quot;.&#039;&#039;&#039;&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;
&#039;&#039;&#039;В данном формате не приходится хранить нули, только значимые коэффициенты, так что обычный формат хранения лучше, когда значимых коэффициентов много. Что значит &amp;quot;много&amp;quot; - указано далее по статье.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Это просто примеры, и рассмотрение их значимости и примечательности не относится к теме разреженных матриц.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Достоинство по сравнению с теми, для которых повторное умножение матрицы на последовательность заполненных векторов не является единственной требуемой матричной операцией.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Медленные альтернативы есть везде. Ту же сортировку можно делать обезьянью, а можно сортировать qsort&#039;ом.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Можно, но не имеет смысла. Как было указано ниже в пункте 2.4 при большом количестве процессоров и малом количестве данных основные временные затраты приходятся именно на пересылки, а не на вычисления, поэтому логично свести их к минимуму. При увеличении числа процессоров число пересылок только увеличится и, разумеется, программа станет работать только дольше.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Конечно нет, потому что всё это - особенности реализации, зависящие от неё (там же не учитывается время на пересылки, время на вывод данных, на их считывание и так далее). Описание алгоритма не зависит от реализации. Если речь идёт в вычисление &amp;quot;старта&amp;quot; и количестве элементов в строке - это аналог вычисление IAA и IAB, на которые слишком малочисленны, а в пункте 1.6 указано, что &amp;quot;Умножения и сложения составляют основную часть алгоритма.&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Целочисленное - потому что захотелось и лично мне так было удобнее при ручном тестировании правильности работы кода. Везде, где идёт определение элементов матрицы и вектора, можно заменить int на double, я считаю, этот вопрос не является принципиальным.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Здесь размер матрицы - это её размерность. Матрицы генерировались случайно, а данные стёрты и восстановить их невозможно, а значит я не могу указать точно, сколько именно было ненулевых элементов. Впрочем, из генератора видно, что число нулевых и ненулевых элементов было где-то 50/50.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Какая структура матрицы, которая использовалась в экспериментах? Какова доля операций чтения из файла в экспериментах?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Что значит &amp;quot;структура матрицы&amp;quot;? Матрица, как я и писала, генерировалась случайно с помощью функций языка Python. Что же касается чтения в самом начале указано, что каждый процессор считает кусок данных, предоставленных ему. Происходит это 1 раз и в самом начале.&#039;&#039;&#039;&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>Blizn</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=19881</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=19881"/>
		<updated>2016-12-02T13:52:46Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Формат RR(C)U */&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;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;
[[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>Blizn</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=19880</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=19880"/>
		<updated>2016-12-02T13:34:10Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Пункт 2.4 */&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;
&#039;&#039;&#039;В качестве теоретической основы использовался Писсанецки, ссылка на него указана выше в статье. Текст использовался именно оттуда, ничего своего я не придумывала. Почему именно 10? Потому что, как было сказано, НЕЛЬЗЯ дать строгого определения тому, начиная с какого количества элементов матрица перестаёт быть плотной и начинает считаться разреженной. А значит, что нельзя сказать, что запрещено определить матрицу именно так. По этой же причине ни одно определение не хуже и не лучше, они просто даны разными людьми в попытках дать более строгое определение, чем просто &amp;quot;много нулей&amp;quot;.&#039;&#039;&#039;&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;
&#039;&#039;&#039;В данном формате не приходится хранить нули, только значимые коэффициенты, так что обычный формат хранения лучше, когда значимых коэффициентов много. Что значит &amp;quot;много&amp;quot; - указано далее по статье.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Это просто примеры, и рассмотрение их значимости и примечательности не относится к теме разреженных матриц.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Достоинство по сравнению с теми, для которых повторное умножение матрицы на последовательность заполненных векторов не является единственной требуемой матричной операцией.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Можно, но не имеет смысла. Как было указано ниже в пункте 2.4 при большом количестве процессоров и малом количестве данных основные временные затраты приходятся именно на пересылки, а не на вычисления, поэтому логично свести их к минимуму. При увеличении числа процессоров число пересылок только увеличится и, разумеется, программа станет работать только дольше.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Конечно нет, потому что всё это - особенности реализации, зависящие от неё (там же не учитывается время на пересылки, время на вывод данных, на их считывание и так далее). Описание алгоритма не зависит от реализации. Если речь идёт в вычисление &amp;quot;старта&amp;quot; и количестве элементов в строке - это аналог вычисление IAA и IAB, на которые слишком малочисленны, а в пункте 1.6 указано, что &amp;quot;Умножения и сложения составляют основную часть алгоритма.&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Целочисленное - потому что захотелось и лично мне так было удобнее при ручном тестировании правильности работы кода. Везде, где идёт определение элементов матрицы и вектора, можно заменить int на double, я считаю, этот вопрос не является принципиальным.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Здесь размер матрицы - это её размерность. Матрицы генерировались случайно, а данные стёрты и восстановить их невозможно, а значит я не могу указать точно, сколько именно было ненулевых элементов. Впрочем, из генератора видно, что число нулевых и ненулевых элементов было где-то 50/50.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Какая структура матрицы, которая использовалась в экспериментах? Какова доля операций чтения из файла в экспериментах?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Что значит &amp;quot;структура матрицы&amp;quot;? Матрица, как я и писала, генерировалась случайно с помощью функций языка Python. Что же касается чтения в самом начале указано, что каждый процессор считает кусок данных, предоставленных ему. Происходит это 1 раз и в самом начале.&#039;&#039;&#039;&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>Blizn</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=19879</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=19879"/>
		<updated>2016-12-02T13:14:32Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Пункт 1.8 */&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;
&#039;&#039;&#039;В качестве теоретической основы использовался Писсанецки, ссылка на него указана выше в статье. Текст использовался именно оттуда, ничего своего я не придумывала. Почему именно 10? Потому что, как было сказано, НЕЛЬЗЯ дать строгого определения тому, начиная с какого количества элементов матрица перестаёт быть плотной и начинает считаться разреженной. А значит, что нельзя сказать, что запрещено определить матрицу именно так. По этой же причине ни одно определение не хуже и не лучше, они просто даны разными людьми в попытках дать более строгое определение, чем просто &amp;quot;много нулей&amp;quot;.&#039;&#039;&#039;&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;
&#039;&#039;&#039;В данном формате не приходится хранить нули, только значимые коэффициенты, так что обычный формат хранения лучше, когда значимых коэффициентов много. Что значит &amp;quot;много&amp;quot; - указано далее по статье.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Это просто примеры, и рассмотрение их значимости и примечательности не относится к теме разреженных матриц.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Достоинство по сравнению с теми, для которых повторное умножение матрицы на последовательность заполненных векторов не является единственной требуемой матричной операцией.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Можно, но не имеет смысла. Как было указано ниже в пункте 2.4 при большом количестве процессоров и малом количестве данных основные временные затраты приходятся именно на пересылки, а не на вычисления, поэтому логично свести их к минимуму. При увеличении числа процессоров число пересылок только увеличится и, разумеется, программа станет работать только дольше.&#039;&#039;&#039;&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>Blizn</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=19878</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=19878"/>
		<updated>2016-12-02T13:09:09Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Свойства алгоритма */&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;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;
[[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>Blizn</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=19877</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=19877"/>
		<updated>2016-12-02T13:06:46Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Последовательная сложность алгоритма */&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;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;
[[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>Blizn</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=19876</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=19876"/>
		<updated>2016-12-02T13:04:34Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Пункт 1.1.2 */&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;
&#039;&#039;&#039;В качестве теоретической основы использовался Писсанецки, ссылка на него указана выше в статье. Текст использовался именно оттуда, ничего своего я не придумывала. Почему именно 10? Потому что, как было сказано, НЕЛЬЗЯ дать строгого определения тому, начиная с какого количества элементов матрица перестаёт быть плотной и начинает считаться разреженной. А значит, что нельзя сказать, что запрещено определить матрицу именно так. По этой же причине ни одно определение не хуже и не лучше, они просто даны разными людьми в попытках дать более строгое определение, чем просто &amp;quot;много нулей&amp;quot;.&#039;&#039;&#039;&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;
&#039;&#039;&#039;В данном формате не приходится хранить нули, только значимые коэффициенты, так что обычный формат хранения лучше, когда значимых коэффициентов много. Что значит &amp;quot;много&amp;quot; - указано далее по статье.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Это просто примеры, и рассмотрение их значимости и примечательности не относится к теме разреженных матриц.&#039;&#039;&#039;&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;
&#039;&#039;&#039;Достоинство по сравнению с теми, для которых повторное умножение матрицы на последовательность заполненных векторов не является единственной требуемой матричной операцией.&#039;&#039;&#039;&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>Blizn</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=19875</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=19875"/>
		<updated>2016-12-02T12:54:08Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Пункт 1.1.1.1 */&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;
&#039;&#039;&#039;В качестве теоретической основы использовался Писсанецки, ссылка на него указана выше в статье. Текст использовался именно оттуда, ничего своего я не придумывала. Почему именно 10? Потому что, как было сказано, НЕЛЬЗЯ дать строгого определения тому, начиная с какого количества элементов матрица перестаёт быть плотной и начинает считаться разреженной. А значит, что нельзя сказать, что запрещено определить матрицу именно так. По этой же причине ни одно определение не хуже и не лучше, они просто даны разными людьми в попытках дать более строгое определение, чем просто &amp;quot;много нулей&amp;quot;.&#039;&#039;&#039;&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;
&#039;&#039;&#039;В данном формате не приходится хранить нули, только значимые коэффициенты, так что обычный формат хранения лучше, когда значимых коэффициентов много. Что значит &amp;quot;много&amp;quot; - указано далее по статье.&#039;&#039;&#039;&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>Blizn</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=19874</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=19874"/>
		<updated>2016-12-02T12:52:14Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Пункт 1.1 */&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;
&#039;&#039;&#039;В качестве теоретической основы использовался Писсанецки, ссылка на него указана выше в статье. Текст использовался именно оттуда, ничего своего я не придумывала. Почему именно 10? Потому что, как было сказано, НЕЛЬЗЯ дать строгого определения тому, начиная с какого количества элементов матрица перестаёт быть плотной и начинает считаться разреженной. А значит, что нельзя сказать, что запрещено определить матрицу именно так. По этой же причине ни одно определение не хуже и не лучше, они просто даны разными людьми в попытках дать более строгое определение, чем просто &amp;quot;много нулей&amp;quot;.&#039;&#039;&#039;&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>Blizn</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=19770</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=19770"/>
		<updated>2016-11-30T22:29:47Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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>Blizn</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=19769</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=19769"/>
		<updated>2016-11-30T22:28:26Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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>Blizn</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=19766</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=19766"/>
		<updated>2016-11-30T21:11:52Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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&#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;
&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>Blizn</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=19742</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=19742"/>
		<updated>2016-11-30T19:23:08Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
Текст использованной в экспериментах реализации (язык С++):&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;
Для формирования входных данных использовался следующий алгоритм (язык Python):&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;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&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>Blizn</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=19642</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=19642"/>
		<updated>2016-11-30T13:37:49Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
Текст использованной в экспериментах реализации (язык С++):&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;
Для формирования входных данных использовался следующий алгоритм (язык Python):&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;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&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>Blizn</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=19640</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=19640"/>
		<updated>2016-11-30T13:34:42Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
Текст использованной в экспериментах реализации (язык С++):&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;
Для формирования входных данных использовался следующий алгоритм (язык Python):&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 Суперкомпьютерного комплекса Московского университета].&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>Blizn</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=19559</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=19559"/>
		<updated>2016-11-29T22:21:22Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров [1 : 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>Blizn</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=19557</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=19557"/>
		<updated>2016-11-29T22:19:34Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров [1 : 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>Blizn</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Blizntime.png&amp;diff=19548</id>
		<title>Файл:Blizntime.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Blizntime.png&amp;diff=19548"/>
		<updated>2016-11-29T21:27:55Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Blizn</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Efficiency(paral).png&amp;diff=19546</id>
		<title>Файл:Efficiency(paral).png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Efficiency(paral).png&amp;diff=19546"/>
		<updated>2016-11-29T21:26:09Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Blizn</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=19512</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=19512"/>
		<updated>2016-11-29T20:11:59Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&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>Blizn</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=19312</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=19312"/>
		<updated>2016-11-28T00:04:57Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
# Один из процессоров выбирается главным;&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; посредством массивов &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;
# Главный процессор &amp;quot;разрезает&amp;quot; матрицу по строкам в зависимости от числа процессоров и отправляет другим процессорам набор данных в виде: вектор &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;c&amp;lt;/math&amp;gt; в зависимости от имеющихся данных;&lt;br /&gt;
# Все процессоры отправляют результаты вычисления главному процессору, главный процессор выводит результат вычислений.&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма умножения разреженной матрицы на вектор. Исследование ещё проводится на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&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>Blizn</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=15803</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=15803"/>
		<updated>2016-11-02T13:44:54Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Выводы для классов архитектур ==&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>Blizn</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=15802</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=15802"/>
		<updated>2016-11-02T13:42:49Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Выводы для классов архитектур ==&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>Blizn</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=15681</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=15681"/>
		<updated>2016-11-01T20:59:41Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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}} x_{i,j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;x_{i,j=j(k)} = 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;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;
== Выводы для классов архитектур ==&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>Blizn</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=15678</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=15678"/>
		<updated>2016-11-01T20:59:22Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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}} x_{i,j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;x_{i,j=j(k)} = 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;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;
== Выводы для классов архитектур ==&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>Blizn</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=15677</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=15677"/>
		<updated>2016-11-01T20:59:03Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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}} x_{i,j=j(k)}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;x_{i,j=j(k)} = 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;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;
== Выводы для классов архитектур ==&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>Blizn</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=15666</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=15666"/>
		<updated>2016-11-01T20:51:30Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
Далее предполагаем, что разреженная матрица общего вида &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;
== Выводы для классов архитектур ==&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>Blizn</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=13574</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=13574"/>
		<updated>2016-10-23T20:51:34Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
Далее предполагаем, что разреженная матрица общего вида &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;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13573</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=13573"/>
		<updated>2016-10-23T20:50:22Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
Далее предполагаем, что разреженная матрица общего вида &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;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Bliznalg.png&amp;diff=13559</id>
		<title>Файл:Bliznalg.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Bliznalg.png&amp;diff=13559"/>
		<updated>2016-10-23T20:23:07Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Blizn загрузил новую версию Файл:Bliznalg.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Blizn</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Bliznalg.png&amp;diff=13557</id>
		<title>Файл:Bliznalg.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Bliznalg.png&amp;diff=13557"/>
		<updated>2016-10-23T20:15:24Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Blizn загрузил новую версию Файл:Bliznalg.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Blizn</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Bliznalg.png&amp;diff=13556</id>
		<title>Файл:Bliznalg.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Bliznalg.png&amp;diff=13556"/>
		<updated>2016-10-23T19:54:39Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Blizn</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=13545</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=13545"/>
		<updated>2016-10-23T19:04:30Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988. 12 с.&amp;lt;/ref&amp;gt;&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;
Далее предполагаем, что разреженная матрица общего вида &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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{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;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;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13541</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=13541"/>
		<updated>2016-10-23T17:35:36Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988. 12 с.&amp;lt;/ref&amp;gt;&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;
Далее предполагаем, что разреженная матрица общего вида &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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{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;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;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13540</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=13540"/>
		<updated>2016-10-23T17:34:38Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988. 12 с.&amp;lt;/ref&amp;gt;&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;
Далее предполагаем, что разреженная матрица общего вида &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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{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;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;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13539</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=13539"/>
		<updated>2016-10-23T17:09:40Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988. 12 с.&amp;lt;/ref&amp;gt;&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;
Далее предполагаем, что разреженная матрица общего вида &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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{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;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;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;), хранимая в форме &#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;j =1,...,m&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;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13538</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=13538"/>
		<updated>2016-10-23T17:09:00Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(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;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988. 12 с.&amp;lt;/ref&amp;gt;&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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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;
Далее предполагаем, что разреженная матрица общего вида &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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{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;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;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;), хранимая в форме &#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;j =1,...,m&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;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13456</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=13456"/>
		<updated>2016-10-22T20:19:53Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(nz)&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;2nz+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;
== Общее описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Разрежённая матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается &#039;&#039;&#039;&#039;&#039;плотной&#039;&#039;&#039;&#039;&#039;.&amp;lt;ref&amp;gt;С.Писсанецки. Технология разреженных матриц. - М.: Мир, 1988. 12 с.&amp;lt;/ref&amp;gt;&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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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}^{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;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}^{nz_{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}^{nz_{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;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;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;
Умножения и сложения составляют &#039;&#039;основную часть алгоритма&#039;&#039;.&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; как аналитически, так и в виде рисунка.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
Первая группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{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;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Blizn</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=13450</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=13450"/>
		<updated>2016-10-22T16:14:14Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(nz)&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;2nz+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;
== Общее описание алгоритма ==&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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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}^{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;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}^{nz_{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}^{nz_{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;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;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;
Умножения и сложения составляют &#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;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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;c_{i}&amp;lt;/math&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Blizn</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=13449</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=13449"/>
		<updated>2016-10-22T16:13:30Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(nz)&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;2nz+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;
== Общее описание алгоритма ==&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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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}^{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;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}^{nz_{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}^{nz_{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;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;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;
Умножения и сложения составляют &#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;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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;с_{i}&amp;lt;/math&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Blizn</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=13448</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=13448"/>
		<updated>2016-10-22T16:13:03Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(nz)&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;2nz+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;
== Общее описание алгоритма ==&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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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}^{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;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}^{nz_{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}^{nz_{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;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;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;
Умножения и сложения составляют &#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;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+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-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
* &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;i+1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, принимая все целочисленные значения.&lt;br /&gt;
&lt;br /&gt;
Аргументы операции следующие:&lt;br /&gt;
*&amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;: &lt;br /&gt;
** при &amp;lt;math&amp;gt;i = 1&amp;lt;/math&amp;gt; — элементы &#039;&#039;входных данных&#039;&#039;, а именно &amp;lt;math&amp;gt;a_{j1}&amp;lt;/math&amp;gt;;&lt;br /&gt;
** при &amp;lt;math&amp;gt;i &amp;gt; 1&amp;lt;/math&amp;gt; — результат срабатывания операции, соответствующей вершине из третьей группы, с координатами &amp;lt;math&amp;gt;i - 1, j, i - 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&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат срабатывания операции является &#039;&#039;выходным данным&#039;&#039; &amp;lt;math&amp;gt;с_{i}&amp;lt;/math&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Blizn</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=13430</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=13430"/>
		<updated>2016-10-22T13:43:17Z</updated>

		<summary type="html">&lt;p&gt;Blizn: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nz&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;2nz+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;
== Общее описание алгоритма ==&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;. Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Ordered&amp;quot; (строчное представление, полное и упорядоченное). В данном формате вместо одного двумерного массива, используются три одномерных. Значения ненулевых элементов матрицы и соответствующие им столбцовые индексы хранятся в этом формате по строкам в двух массивах &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;
Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Unordered&amp;quot; (строчное представление, полное, но неупорядоченное). Формат &#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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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}^{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;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;/div&gt;</summary>
		<author><name>Blizn</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&amp;diff=13429</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&amp;diff=13429"/>
		<updated>2016-10-22T13:21:07Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Близнякова Ирина Валерьевна, 611 группа.&lt;/div&gt;</summary>
		<author><name>Blizn</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=13427</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=13427"/>
		<updated>2016-10-22T13:20:42Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Blizn переименовал страницу [[Участник:Близнякова Ирина/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы н…&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nz&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;2nz+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;
== Общее описание алгоритма ==&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;. Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Ordered&amp;quot; (строчное представление, полное и упорядоченное). В данном формате вместо одного двумерного массива, используются три одномерных. Значения ненулевых элементов матрицы и соответствующие им столбцовые индексы хранятся в этом формате по строкам в двух массивах &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;
Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Unordered&amp;quot; (строчное представление, полное, но неупорядоченное). Формат &#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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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;/div&gt;</summary>
		<author><name>Blizn</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&amp;diff=13426</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&amp;diff=13426"/>
		<updated>2016-10-22T13:18:57Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Создана пустая страница&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Blizn</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=13425</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=13425"/>
		<updated>2016-10-22T13:15:58Z</updated>

		<summary type="html">&lt;p&gt;Blizn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nz&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;2nz+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;
== Общее описание алгоритма ==&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;. Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Ordered&amp;quot; (строчное представление, полное и упорядоченное). В данном формате вместо одного двумерного массива, используются три одномерных. Значения ненулевых элементов матрицы и соответствующие им столбцовые индексы хранятся в этом формате по строкам в двух массивах &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;
Сокращенное название данного формата происходит от английского словосочетания &amp;quot;Row - wise Representation Complete and Unordered&amp;quot; (строчное представление, полное, но неупорядоченное). Формат &#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;
&#039;&#039;&#039;Умножение разреженной матрицы на вектор&#039;&#039;&#039; - важным приложением этих алгоритмов является вычисление векторов Ланцоша, необходимое при итерационном решении линейных уравнений методом сопряженных градиентов, а также при вычислении собственных значений и собственных векторов матрицы. Достоинство этих процедур, с вычислительной точки зрения, состоит в том, что единственная требуемая матричная операция - это повторное умножение матрицы на последовательность заполненных векторов; сама матрица не меняется. &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;/div&gt;</summary>
		<author><name>Blizn</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=13422</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=13422"/>
		<updated>2016-10-22T10:05:47Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Blizn переименовал страницу [[Участник:Иванов Иван/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на век…&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ыыы&lt;/div&gt;</summary>
		<author><name>Blizn</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=13420</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=13420"/>
		<updated>2016-10-22T10:05:29Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Blizn переименовал страницу Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор. 2 в [[Участник:Ива…&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ыыы&lt;/div&gt;</summary>
		<author><name>Blizn</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=13419</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=13419"/>
		<updated>2016-10-22T09:58:35Z</updated>

		<summary type="html">&lt;p&gt;Blizn: Новая страница: «ыыы»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ыыы&lt;/div&gt;</summary>
		<author><name>Blizn</name></author>
	</entry>
</feed>