<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9"/>
	<updated>2026-10-22T18:13:19Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=20606</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=20606"/>
		<updated>2016-12-10T17:08:53Z</updated>

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

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

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

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

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

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

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

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

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

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

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

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

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

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Dan}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_more_points.png|thumb|center|1000px|Рис.3 Умножение разреженной матрицы на вектор. Масштабируемость]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_eff_new.png|thumb|center|1000px|Рис.4 Умножение разреженной матрицы на вектор. Эффективность]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17508</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17508"/>
		<updated>2016-11-15T23:22:12Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Dan}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_more_points.png|thumb|center|1000px|Рис.3 Умножение разреженной матрицы на вектор. Масштабируемость]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_eff.png|thumb|center|1000px|Рис.4 Умножение разреженной матрицы на вектор. Эффективность]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17505</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17505"/>
		<updated>2016-11-15T22:45:53Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Dan}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot_more_points.png|thumb|center|1000px|Рис.3 Умножение разреженной матрицы на вектор. MPI]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17310</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17310"/>
		<updated>2016-11-15T16:10:50Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Dan}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:plot.png|thumb|center|1000px|Рис.3 Умножение разреженной матрицы на вектор. MPI]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17255</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17255"/>
		<updated>2016-11-15T13:36:13Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17254</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17254"/>
		<updated>2016-11-15T13:33:43Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17253</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17253"/>
		<updated>2016-11-15T13:32:02Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17252</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17252"/>
		<updated>2016-11-15T13:31:07Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Опишем граф алгоритма.&lt;br /&gt;
&lt;br /&gt;
Граф алгоритма состоит из двух групп вершин, расположенных в целочисленных узлах двух областей одной размерности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a \cdot b&amp;lt;/math&amp;gt;. Координаты области следующие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все натуральные значения;&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; — меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; k &amp;lt;/math&amp;gt;, принимая все натуральные значения,&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;. (На рисунке вместо обозначения &#039;&#039;row&#039;&#039; использовано обозначение &#039;&#039;r&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Результаты операции - &#039;&#039;&#039;промежуточные&#039;&#039;&#039; данные алгоритма.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Вторая&#039;&#039;&#039; группа вершин расположена в двумерной области, соответствующая ей операция вычисляет функцию &amp;lt;math&amp;gt;a + b&amp;lt;/math&amp;gt;. &lt;br /&gt;
Координаты области таковы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;N-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения;&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - меняется в диапазоне от &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;k-1&amp;lt;/math&amp;gt;, принимая все целочисленные значения,&lt;br /&gt;
где &amp;lt;math&amp;gt;k = k(i) = row[i+1]-row[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Результат операции:&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j &amp;lt; k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;промежуточным&#039;&#039;&#039; данным алгоритма;&lt;br /&gt;
&amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; при &amp;lt;math&amp;gt;j = k - 1&amp;lt;/math&amp;gt; является &#039;&#039;&#039;выходным&#039;&#039;&#039; данным &amp;lt;math&amp;gt;out[i]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Описанный граф изображен на Рис.2. Здесь вершины первой группы обозначены красным цветом и отмечены знаком умножения, вершины второй - зелёным цветом и знаком сложения. Вершины, соответствующие входным данным обозначены белым цветом и выходным - синим.&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17249</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17249"/>
		<updated>2016-11-15T13:15:00Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
Минимальное и максимальное значение &#039;&#039;j&#039;&#039; узнается из вектора &#039;&#039;row&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17248</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17248"/>
		<updated>2016-11-15T13:12:52Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Предполагается, что матрица представлена в разреженном строчном формате.&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
Индекс &#039;&#039;j&#039;&#039; показывает с какого по какой элемент нужно считать из &#039;&#039;val&#039;&#039; (вектор с ненулевыми значениями матрицы), а также позволяет определить в каких столбцах расположены эти значения в матрице (с помощью вектора &#039;&#039;col&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|1000px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17247</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17247"/>
		<updated>2016-11-15T13:05:49Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:new_sparse.png|thumb|center|700px|Рис.2 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17245</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=17245"/>
		<updated>2016-11-15T13:03:53Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15901</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15901"/>
		<updated>2016-11-03T16:58:22Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
[1] Писсанецки С. Технология разреженных матриц. - М.: Мир, 1988. — 410 с.&lt;br /&gt;
&lt;br /&gt;
[2] https://software.intel.com/sites/default/files/m/d/4/1/d/8/LW_SparseMM_ppt.pdf&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15537</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15537"/>
		<updated>2016-11-01T12:07:42Z</updated>

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

		<summary type="html">&lt;p&gt;Сергей: Полностью удалено содержимое страницы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15533</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15533"/>
		<updated>2016-11-01T11:53:42Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, [https://software.intel.com/en-us/intel-mkl Intel Math Kernel Library], базирующуюся на библиотеках BLAS и LAPACK, также математических пакет [http://matlab.ru/products/matlab Matlab] имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15529</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15529"/>
		<updated>2016-11-01T11:48:19Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Внешний цикл - цикл по элементам выходного вектора. Внутренний - цикл по строкам разреженной матрицы.&lt;br /&gt;
Во внутреннем цикле реализовано накопление сумм произведений в выходной элемент.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15525</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15525"/>
		<updated>2016-11-01T11:38:31Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций, где &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; - количество ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15523</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15523"/>
		<updated>2016-11-01T11:37:49Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Всего &amp;lt;math&amp;gt;2NZ&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9&amp;diff=15520</id>
		<title>Обсуждение участника:Сергей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9&amp;diff=15520"/>
		<updated>2016-11-01T11:28:38Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Пункт 1.5 =&lt;br /&gt;
Добавить описание к псевдокоду.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
Указать итоговую сложность.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.7 =&lt;br /&gt;
Добавить ссылки на реализации.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
Отсутствует раздел источников, необходимо добавить.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15519</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15519"/>
		<updated>2016-11-01T11:27:47Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15518</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15518"/>
		<updated>2016-11-01T11:27:29Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|left|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15517</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15517"/>
		<updated>2016-11-01T11:26:54Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|thumb|center|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15516</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15516"/>
		<updated>2016-11-01T11:26:03Z</updated>

		<summary type="html">&lt;p&gt;Сергей: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|Рис.1 Умножение разреженной матрицы на вектор. Информационный граф]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15515</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15515"/>
		<updated>2016-11-01T11:21:23Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9&amp;diff=15513</id>
		<title>Обсуждение участника:Сергей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9&amp;diff=15513"/>
		<updated>2016-11-01T11:19:43Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Пункт 1.3 =&lt;br /&gt;
Лучше избегать ссылок на соседние пункты. Подразделы д.б. самодостаточны.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.4 =&lt;br /&gt;
Следует просто привести описание макроструктуры, без ссылки на другие пункты.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
Добавить описание к псевдокоду.&lt;br /&gt;
Если заимствован, дать ссылку на источник.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
Указать итоговую сложность.&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.7 =&lt;br /&gt;
Оформить как рисунок с номером и подписью.&lt;br /&gt;
Если рисунок заимствован, надо дать ссылку на источник.&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.7 =&lt;br /&gt;
Добавить ссылки на реализации.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
Отсутствует раздел источников, необходимо добавить.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15492</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=15492"/>
		<updated>2016-11-01T10:52:41Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Автор: [[U:Сергей|Герасимов Сергей]] (619)&lt;br /&gt;
&lt;br /&gt;
= Содержание =&lt;br /&gt;
&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8591</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8591"/>
		<updated>2016-10-15T01:00:07Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;Z-1&amp;lt;/math&amp;gt; операция сложения, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8584</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8584"/>
		<updated>2016-10-15T00:47:10Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;\log_2{Z}&amp;lt;/math&amp;gt; ярусов сложений, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм обладает свойством детерминированности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8570</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8570"/>
		<updated>2016-10-15T00:31:36Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;\log_2{Z}&amp;lt;/math&amp;gt; ярусов сложений, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм не обладает свойством детерминированности, так как не известна исходная структура матрицы и число ненулевых компонент в разных строках может отличаться.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Эффективная работа с разреженными матрицами реализована во многих библиотеках, например, Intel Math Kernel Library, базирующуюся на библиотеках BLAS и LAPACK, также математических пакет Matlab имеет собственную реализацию.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8545</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8545"/>
		<updated>2016-10-15T00:11:54Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;\log_2{Z}&amp;lt;/math&amp;gt; ярусов сложений, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм не обладает свойством детерминированности, так как не известна исходная структура матрицы и число ненулевых компонент в разных строках может отличаться.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8534</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8534"/>
		<updated>2016-10-15T00:02:49Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;\log_2{Z}&amp;lt;/math&amp;gt; ярусов сложений, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в случае неограниченных ресурсов, как хорошо видно, является &#039;&#039;линейным&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма, как отношение числа операций к суммарному объему входных и выходных данных – чуть меньше &#039;&#039;единицы&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8513</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8513"/>
		<updated>2016-10-14T23:52:08Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Элементы из массива val умножаются на элементы из массива vec с соответствующим индексом. Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;\log_2{Z}&amp;lt;/math&amp;gt; ярусов сложений, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Сергей</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:Sparse.jpg&amp;diff=8510</id>
		<title>Файл:Sparse.jpg</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:Sparse.jpg&amp;diff=8510"/>
		<updated>2016-10-14T23:50:03Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8499</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8499"/>
		<updated>2016-10-14T23:34:23Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse_matrix.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
При наличии бесконечного числа процессоров для умножения разреженной матрицы на вектор потребуется:&lt;br /&gt;
&lt;br /&gt;
~ 1 ярус умножений&lt;br /&gt;
&lt;br /&gt;
~ &amp;lt;math&amp;gt;\log_2{Z}&amp;lt;/math&amp;gt; ярусов сложений, где Z - максимальное число ненулевых элементов в строке.&lt;br /&gt;
&lt;br /&gt;
Максимальное число требуемых процессоров - NZ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
~ вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
~ вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
~ вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8462</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8462"/>
		<updated>2016-10-14T23:13:22Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse_matrix.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.8 Ресурс параллелизма алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.9 Входные и выходные данные алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его как val);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива val (обозначим его как col);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его row);&lt;br /&gt;
&lt;br /&gt;
~ вектор, на который будет умножаться матрица (обозначим его vec).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для матрицы размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt;, содержащей в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
вектор val - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
вектор col - NZ элементов;&lt;br /&gt;
&lt;br /&gt;
вектор row - N+1 элемент;&lt;br /&gt;
&lt;br /&gt;
вектор vec - M элементов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вектор out размером N.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.10 Свойства алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2 Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.7 Существующие реализации алгоритма&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8443</id>
		<title>Участник:Сергей/Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D0%B9/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=8443"/>
		<updated>2016-10-14T22:53:32Z</updated>

		<summary type="html">&lt;p&gt;Сергей: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 1 Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.1 Общее описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Разреженная матрица&#039;&#039;&#039; — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
&lt;br /&gt;
Нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. Для матрицы порядка n число ненулевых элементов:&lt;br /&gt;
&lt;br /&gt;
~ есть O(n). Такое определение подходит разве что для теоретического анализа асимптотических свойств матричных алгоритмов;&lt;br /&gt;
&lt;br /&gt;
~ в каждой строке не превышает 10 в типичном случае;&lt;br /&gt;
&lt;br /&gt;
~ ограничено &amp;lt;math&amp;gt;n^{1+\gamma}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\gamma &amp;lt; 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных.&lt;br /&gt;
&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Существуют различные форматы хранения разреженных матриц.&#039;&#039;&#039; Одни предназначены для хранения матриц специального вида (например, ленточных), другие обеспечивают работу с матрицами общего вида. Ниже рассмотрим некоторые весьма распространенные способы представления разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
По-видимому, наиболее очевидным способом хранения произвольной разреженной матрицы является &#039;&#039;&#039;координатный формат&#039;&#039;&#039;: хранятся только ненулевые элементы матрицы, и их координаты (номера строк и столбцов). При данном подходе хранение матрицы A можно обеспечить в трех одномерных массивах:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A (обозначим его как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров строк матрицы A, соответствующих элементам массива values (обозначим его как rows);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов матрицы A, соответствующих элементам массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
Данный способ представления называют полным, поскольку представлена вся матрица А, и неупорядоченным, поскольку элементы матрицы могут храниться в произвольном порядке.&lt;br /&gt;
&lt;br /&gt;
Хотя многие математические библиотеки поддерживают матрично-векторные операции в координатном формате, данный формат обеспечивает медленный доступ к элементам матрицы, и является затратным по используемой памяти. В рассмотренном выше примере избыточность по памяти образом проявляется в массиве rows, в котором строчные координаты хранятся неоптимальным образом.&lt;br /&gt;
&lt;br /&gt;
Перейдем далее к рассмотрению более экономных форматов хранения. &#039;&#039;&#039;Разреженный строчный формат&#039;&#039;&#039; - это одна из наиболее широко используемых схем хранения разреженных матриц. Эта схема предъявляет минимальные требования к памяти и в то же время оказывается очень удобной для нескольких важных операций над разреженными матрицами: сложения, умножения, перестановок строк и столбцов, транспонирования, решения линейных систем с разреженными матрицами коэффициентов как прямыми, так и итерационными методами и т. д.&lt;br /&gt;
&lt;br /&gt;
В соответствии с рассматриваемой схемой для хранения матрицы A требуется три одномерных массива:&lt;br /&gt;
&lt;br /&gt;
~ массив ненулевых элементов матрицы A, в котором они перечислены по строкам от первой до последней (обозначим его опять как values);&lt;br /&gt;
&lt;br /&gt;
~ массив номеров столбцов для соответствующих элементов массива values (обозначим его как cols);&lt;br /&gt;
&lt;br /&gt;
~ массив указателей позиций, с которых начинается описание очередной строки (обозначим его pointer). Описание k-й строки хранится в позициях с pointer[k]-й по (pointer[k+1]–1)-ю массивов values и cols. Если pointer[k]=pointer[k+1], то k-я строка пустая. Если матрица A состоит из n строк, то длина массива pointer будет n+1.&lt;br /&gt;
&lt;br /&gt;
Данный способ представления также является полным, и упорядоченным, поскольку элементы каждой строки хранятся в соответствии с возрастанием столбцовых индексов.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что объем памяти, требуемый для хранения вектора pointer, значительно меньше, чем для хранения вектора rows. Более того, разреженный строчный формат обеспечивает эффективный доступ к строчкам матрицы; доступ к столбцам по прежнему затруднен. Поэтому предпочтительно использовать этот способ хранения в тех алгоритмах, в которых преобладают строчные операции.&lt;br /&gt;
&lt;br /&gt;
Существует также &#039;&#039;&#039;разреженный столбцовый формат&#039;&#039;&#039;, который строится аналогичным способом.&lt;br /&gt;
&lt;br /&gt;
Теперь, разобравшись со способами хранения разреженных матриц, можно перейти к &#039;&#039;алгоритму умножения разреженной матрицы на вектор&#039;&#039;. Умножение матрицы на вектор является подзадачей для нахождения решений СЛАУ итерационными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.2 Математическое описание алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Пусть матрица размером &amp;lt;math&amp;gt;N\times M&amp;lt;/math&amp;gt; содержит в себе &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; ненулевых элементов, где &amp;lt;math&amp;gt;NZ\ll N^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Условимся использовать строчный формат хранения матрицы, который описан выше.&lt;br /&gt;
&lt;br /&gt;
На входе у нас 4 массива: val(ненулевые элементы матрицы), col(номера столбцов), row(массив указателей) и vec(вектор, на который мы умножаем матрицу).&lt;br /&gt;
&lt;br /&gt;
На выходе получим вектор out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}, \ i=\overline{0,N-1}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - число строк матрицы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.3 Вычислительное ядро алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ядром алгоритма является вычисление сумм произведений, описанное в [[предыдущем пункте]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;out_i = \sum_{j=row_i}^{row_{i+1} - 1} val_j \cdot vec_{col_j}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итого: &amp;lt;math&amp;gt;NZ&amp;lt;/math&amp;gt; умножений + &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.4 Макроструктура алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Как видно из [[описания алгоритма]], метод состоит из вычисления неполных скалярных произведений.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.5 Схема реализации последовательного алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    for(i=0; i&amp;lt;N; i++)&lt;br /&gt;
    {&lt;br /&gt;
        out[i]=0;&lt;br /&gt;
        for(j=row[i]; j&amp;lt;row[i+1]; j++)&lt;br /&gt;
        {&lt;br /&gt;
            out[i] += val[j]*vec[col[j]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.6 Последовательная сложность алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ NZ&amp;lt;/math&amp;gt; умножений &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\bullet \ x&amp;lt;/math&amp;gt; сложений(&amp;lt;math&amp;gt;NZ-N&amp;lt;x&amp;lt;NZ-1&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.7 Информационный граф&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Файл:sparse_matrix.jpg|500px|при N=3]]&lt;br /&gt;
&lt;br /&gt;
Черным отмечены ненулевые элементы. При увеличении числа N граф будет аналогичным.&lt;/div&gt;</summary>
		<author><name>Сергей</name></author>
	</entry>
</feed>