<?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=Trrufina</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=Trrufina"/>
	<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/Trrufina"/>
	<updated>2026-10-22T20:01: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%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20730</id>
		<title>Обсуждение участницы:Trrufina</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20730"/>
		<updated>2016-12-12T11:50:59Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Хорошая работа. Есть несколько замечаний&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Спасибо! Внесла небольшие правки в статью по замечаниям. На некоторые замечания ответила в этом тексте&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это предложение нужно переформулировать. Разреженные матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
&#039;&#039;&#039;Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
С какой точки зрения данный формат является «наиболее удобным»?&lt;br /&gt;
&lt;br /&gt;
Данный раздел хорошо бы дополнить хотя бы кратким упоминанием других способов хранения разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет ли влиять выполнение свойства ассоциативности для сложения на детерминированность алгоритма? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
&lt;br /&gt;
Лучше использовать одинаковую индексацию для псевдокода алгоритма (1.4) и для схемы реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Оценка для числа сложений похоже не совсем правильная для алгоритма в 1.5 (например, для матрицы с одним ненулевым элементом).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
&lt;br /&gt;
Можно ли записать параллельный алгоритм, использующий больше чем n процессоров, где n - число строк(столбцов)?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.9 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В оценке не учитывается пункт 1 – размер разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Учитываются, размер разреженной матрицы n, хранится она в формате CSR: 2 nnz + n + 1 памяти, плюс x, плотный вектор размера n&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
&lt;br /&gt;
Непонятно какая реализация алгоритма использовалась в экспериментах. Если это собственная реализация, то нужно кратко описать язык программирования, библиотеки, которые использовались и т.п. &lt;br /&gt;
&#039;&#039;&#039;Собственная реализация на языке C, никаких дополнительных библиотек кроме стандартных библиотек языка и mpi.h не использовалось&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. управляющий процессор разделяет матрицу на блоки в зависимости от числа процессоров и рассылает остальным процессорам строки матрицы и вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Разделение матрицы идет только по строкам или по блокам матрицы?&lt;br /&gt;
&#039;&#039;&#039;Разделение происходит по блокам, которые содержат целое число строк. Число строк на каждом процессоре равно  &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатка - исправила&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нужно описать, что подразумевается под «Matrix size» на рисунках, число ненулевых элементов или размерность матрицы, и указать обе величины в численных экспериментах. &lt;br /&gt;
&#039;&#039;&#039;«Matrix size» равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. В экспериментах число ненулевых элементов задавалось как &amp;lt;math&amp;gt;n * \sqrt{n}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Улучшенный алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;4. управляющий (нулевой) процессор собирает результат или же каждый процессор записывает свою часть результата (при помощи процедур параллельной записи)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Если в расчет и 1-го алгоритма и «улучшенного алгоритма» входила параллельная запись в файл, а не просто сборка данных на управляющем процессоре, то нужно это явно уточнить в тексте.&lt;br /&gt;
&#039;&#039;&#039;Нет, запись в файл не производилась в экспериментах&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатки - исправила.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Тестирование производилось на кластере cluster2 ИВМ РАН.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно добавить ссылку на описание кластера.&lt;br /&gt;
Почему не проводились эксперименты только на очередях из однородных ядер на кластере ИВМ?&lt;br /&gt;
&#039;&#039;&#039;Потому что очереди из однородных ядер содержат 16 или 32 ядер, мне этого было недостаточно. Cсылку добавила.&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20729</id>
		<title>Обсуждение участницы:Trrufina</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20729"/>
		<updated>2016-12-12T11:49:13Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Пункт 2.4 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Хорошая работа. Есть несколько замечаний&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это предложение нужно переформулировать. Разреженные матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
&#039;&#039;&#039;Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
С какой точки зрения данный формат является «наиболее удобным»?&lt;br /&gt;
&lt;br /&gt;
Данный раздел хорошо бы дополнить хотя бы кратким упоминанием других способов хранения разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет ли влиять выполнение свойства ассоциативности для сложения на детерминированность алгоритма? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
&lt;br /&gt;
Лучше использовать одинаковую индексацию для псевдокода алгоритма (1.4) и для схемы реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Оценка для числа сложений похоже не совсем правильная для алгоритма в 1.5 (например, для матрицы с одним ненулевым элементом).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
&lt;br /&gt;
Можно ли записать параллельный алгоритм, использующий больше чем n процессоров, где n - число строк(столбцов)?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.9 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В оценке не учитывается пункт 1 – размер разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Учитываются, размер разреженной матрицы n, хранится она в формате CSR: 2 nnz + n + 1 памяти, плюс x, плотный вектор размера n&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
&lt;br /&gt;
Непонятно какая реализация алгоритма использовалась в экспериментах. Если это собственная реализация, то нужно кратко описать язык программирования, библиотеки, которые использовались и т.п. &lt;br /&gt;
&#039;&#039;&#039;Собственная реализация на языке C, никаких дополнительных библиотек кроме стандартных библиотек языка и mpi.h не использовалось&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. управляющий процессор разделяет матрицу на блоки в зависимости от числа процессоров и рассылает остальным процессорам строки матрицы и вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Разделение матрицы идет только по строкам или по блокам матрицы?&lt;br /&gt;
&#039;&#039;&#039;Разделение происходит по блокам, которые содержат целое число строк. Число строк на каждом процессоре равно  &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатка - исправила&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нужно описать, что подразумевается под «Matrix size» на рисунках, число ненулевых элементов или размерность матрицы, и указать обе величины в численных экспериментах. &lt;br /&gt;
&#039;&#039;&#039;«Matrix size» равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. В экспериментах число ненулевых элементов задавалось как &amp;lt;math&amp;gt;n * \sqrt{n}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Улучшенный алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;4. управляющий (нулевой) процессор собирает результат или же каждый процессор записывает свою часть результата (при помощи процедур параллельной записи)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Если в расчет и 1-го алгоритма и «улучшенного алгоритма» входила параллельная запись в файл, а не просто сборка данных на управляющем процессоре, то нужно это явно уточнить в тексте.&lt;br /&gt;
&#039;&#039;&#039;Нет, запись в файл не производилась в экспериментах&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатки - исправила.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Тестирование производилось на кластере cluster2 ИВМ РАН.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно добавить ссылку на описание кластера.&lt;br /&gt;
Почему не проводились эксперименты только на очередях из однородных ядер на кластере ИВМ?&lt;br /&gt;
&#039;&#039;&#039;Потому что очереди из однородных ядер содержат 16 или 32 ядер, мне этого было недостаточно. Cсылку добавила.&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20728</id>
		<title>Обсуждение участницы:Trrufina</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20728"/>
		<updated>2016-12-12T11:48:32Z</updated>

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

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

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

		<summary type="html">&lt;p&gt;Trrufina: /* Пункт 2.4 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Хорошая работа. Есть несколько замечаний&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это предложение нужно переформулировать. Разреженные матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
&#039;&#039;&#039;Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
С какой точки зрения данный формат является «наиболее удобным»?&lt;br /&gt;
&lt;br /&gt;
Данный раздел хорошо бы дополнить хотя бы кратким упоминанием других способов хранения разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет ли влиять выполнение свойства ассоциативности для сложения на детерминированность алгоритма? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
&lt;br /&gt;
Лучше использовать одинаковую индексацию для псевдокода алгоритма (1.4) и для схемы реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Оценка для числа сложений похоже не совсем правильная для алгоритма в 1.5 (например, для матрицы с одним ненулевым элементом).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
&lt;br /&gt;
Можно ли записать параллельный алгоритм, использующий больше чем n процессоров, где n - число строк(столбцов)?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.9 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В оценке не учитывается пункт 1 – размер разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Учитываются, размер разреженной матрицы n, хранится она в формате CSR: 2 nnz + n + 1 памяти, плюс x, плотный вектор размера n&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
&lt;br /&gt;
Непонятно какая реализация алгоритма использовалась в экспериментах. Если это собственная реализация, то нужно кратко описать язык программирования, библиотеки, которые использовались и т.п. &lt;br /&gt;
&#039;&#039;&#039;Собственная реализация на языке C, никаких дополнительных библиотек кроме стандартных библиотек языка и mpi.h не использовалось&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. управляющий процессор разделяет матрицу на блоки в зависимости от числа процессоров и рассылает остальным процессорам строки матрицы и вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Разделение матрицы идет только по строкам или по блокам матрицы?&lt;br /&gt;
&#039;&#039;&#039;Разделение происходит по блокам, которые содержат целое число строк. Число строк на каждом процессоре равно  &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатка - исправила&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нужно описать, что подразумевается под «Matrix size» на рисунках, число ненулевых элементов или размерность матрицы, и указать обе величины в численных экспериментах. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Улучшенный алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;4. управляющий (нулевой) процессор собирает результат или же каждый процессор записывает свою часть результата (при помощи процедур параллельной записи)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Если в расчет и 1-го алгоритма и «улучшенного алгоритма» входила параллельная запись в файл, а не просто сборка данных на управляющем процессоре, то нужно это явно уточнить в тексте.&lt;br /&gt;
&#039;&#039;&#039;Нет, запись в файл не производилась в экспериментах&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатки - исправила.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Тестирование производилось на кластере cluster2 ИВМ РАН.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно добавить ссылку на описание кластера.&lt;br /&gt;
Почему не проводились эксперименты только на очередях из однородных ядер на кластере ИВМ?&lt;br /&gt;
&#039;&#039;&#039;Потому что очереди из однородных ядер содержат 16 или 32 ядер, мне этого было недостаточно&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20724</id>
		<title>Обсуждение участницы:Trrufina</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20724"/>
		<updated>2016-12-12T11:33:07Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Пункт 1.9 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Хорошая работа. Есть несколько замечаний&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.1 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Это предложение нужно переформулировать. Разреженные матрицы часто возникают при решении дифференциальных уравнений именно численными методами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.2 =&lt;br /&gt;
&#039;&#039;&#039;Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
С какой точки зрения данный формат является «наиболее удобным»?&lt;br /&gt;
&lt;br /&gt;
Данный раздел хорошо бы дополнить хотя бы кратким упоминанием других способов хранения разреженных матриц.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Будет ли влиять выполнение свойства ассоциативности для сложения на детерминированность алгоритма? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.5 =&lt;br /&gt;
&lt;br /&gt;
Лучше использовать одинаковую индексацию для псевдокода алгоритма (1.4) и для схемы реализации алгоритма.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.6 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Оценка для числа сложений похоже не совсем правильная для алгоритма в 1.5 (например, для матрицы с одним ненулевым элементом).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.8 =&lt;br /&gt;
&lt;br /&gt;
Можно ли записать параллельный алгоритм, использующий больше чем n процессоров, где n - число строк(столбцов)?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Пункт 1.9 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В оценке не учитывается пункт 1 – размер разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Учитываются, размер разреженной матрицы n, хранится она в формате CSR: 2 nnz + n + 1 памяти, плюс x, плотный вектор размера n&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Пункт 2.4 =&lt;br /&gt;
&lt;br /&gt;
Непонятно какая реализация алгоритма использовалась в экспериментах. Если это собственная реализация, то нужно кратко описать язык программирования, библиотеки, которые использовались и т.п. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. управляющий процессор разделяет матрицу на блоки в зависимости от числа процессоров и рассылает остальным процессорам строки матрицы и вектор&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Разделение матрицы идет только по строкам или по блокам матрицы?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатка - &#039;&#039;&#039;Данный алгоритм несмотря на кажщуюся простоту&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нужно описать, что подразумевается под «Matrix size» на рисунках, число ненулевых элементов или размерность матрицы, и указать обе величины в численных экспериментах. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Улучшенный алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;4. управляющий (нулевой) процессор собирает результат или же каждый процессор записывает свою часть результата (при помощи процедур параллельной записи)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Если в расчет и 1-го алгоритма и «улучшенного алгоритма» входила параллельная запись в файл, а не просто сборка данных на управляющем процессоре, то нужно это явно уточнить в тексте.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Опечатки - Следует заметить, что в данной реализации матрица генерировалась при помощи случайных &#039;&#039;&#039;числел&#039;&#039;&#039;, и кроме того кластер, на котором &#039;&#039;&#039;прозиводились&#039;&#039;&#039; эксперименты не является однородным, различные ядра имеют различные характеристики, вследствие чего возникает &amp;quot;рельефность&amp;quot; производительности и эффективности.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Тестирование производилось на кластере cluster2 ИВМ РАН.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Нужно добавить ссылку на описание кластера.&lt;br /&gt;
Почему не проводились эксперименты только на очередях из однородных ядер на кластере ИВМ?&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20723</id>
		<title>Обсуждение участницы:Trrufina</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D1%86%D1%8B:Trrufina&amp;diff=20723"/>
		<updated>2016-12-12T11:31:26Z</updated>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<summary type="html">&lt;p&gt;Trrufina: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
Руфина Третьякова отвечает за программную реализацию алгоритма, Екатерина Буторина - за написание статьи.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф рассмотрим процесс вычисления значения одного элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Число последовательных ярусов равно числу последовательных операций -- &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; (в данном случае умножение и сложение будем считать за одну операцию).&lt;br /&gt;
Если же вычисления всех &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; производить параллельно, на каждом ярусе будет производиться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:1111.jpg|800x800px|center|thumb|Информационный граф алгоритма умножения разреженной матрицы на плотный вектор &lt;br /&gt;
(Рисунок составлен самостоятельно)]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Возможность параллельной реализации алгоритма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:perf_clr.png|800x800px|center|thumb|1 ]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:perf_drt.png|800x800px|center|thumb|1 ]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:effc_clr.png|800x800px|center|thumb|1 ]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:effc_drt.png|800x800px|center|thumb|1 ]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</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:Perf_drt.png&amp;diff=15042</id>
		<title>Файл:Perf drt.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Perf_drt.png&amp;diff=15042"/>
		<updated>2016-10-31T11:37:27Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Trrufina</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:Perf_clr.png&amp;diff=15041</id>
		<title>Файл:Perf clr.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Perf_clr.png&amp;diff=15041"/>
		<updated>2016-10-31T11:37:06Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Trrufina</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:Effc_drt.png&amp;diff=15040</id>
		<title>Файл:Effc drt.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Effc_drt.png&amp;diff=15040"/>
		<updated>2016-10-31T11:35:59Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Trrufina</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:Effc_clr.png&amp;diff=15038</id>
		<title>Файл:Effc clr.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Effc_clr.png&amp;diff=15038"/>
		<updated>2016-10-31T11:35:01Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=14234</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=14234"/>
		<updated>2016-10-27T17:57:07Z</updated>

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

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

		<summary type="html">&lt;p&gt;Trrufina: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф рассмотрим процесс вычисления значения одного элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Число последовательных ярусов равно числу последовательных операций -- &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; (в данном случае умножение и сложение будем считать за одну операцию).&lt;br /&gt;
Если же вычисления всех &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; производить параллельно, на каждом ярусе будет производиться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:1111.jpg|80x80px|center|frame|Информационный граф алгоритма умножения разреженной матрицы на плотный вектор]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Возможность параллельной реализации алгоритма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6920</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6920"/>
		<updated>2016-10-13T20:49:02Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф рассмотрим процесс вычисления значения одного элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Число последовательных ярусов равно числу последовательных операций -- &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; (в данном случае умножение и сложение будем считать за одну операцию).&lt;br /&gt;
Если же вычисления всех &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; производить параллельно, на каждом ярусе будет производиться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:1111.jpg|800x800px|center|frame|Информационный граф алгоритма умножения разреженной матрицы на плотный вектор]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Возможность параллельной реализации алгоритма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6914</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6914"/>
		<updated>2016-10-13T20:47:07Z</updated>

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

		<summary type="html">&lt;p&gt;Trrufina: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф рассмотрим процесс вычисления значения одного элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Число последовательных ярусов равно числу последовательных операций -- &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; (в данном случае умножение и сложение будем считать за одну операцию).&lt;br /&gt;
Если же вычисления всех &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; производить параллельно, на каждом ярусе будет производиться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Возможность параллельной реализации алгоритма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6866</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6866"/>
		<updated>2016-10-13T20:10:59Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф рассмотрим процесс вычисления значения одного элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Число последовательных ярусов равно числу последовательных операций -- &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; (в данном случае умножение и сложение будем считать за одну операцию).&lt;br /&gt;
Если же вычисления всех &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; производить параллельно, на каждом ярусе будет производиться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Возможность параллельной реализации алгоритма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6854</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6854"/>
		<updated>2016-10-13T20:01:45Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф &lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычисление &lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как было указано ранее, возможность параллелизма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Замечание:&#039;&#039; если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6852</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6852"/>
		<updated>2016-10-13T20:01:24Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф &lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычисление &lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как было указано ранее, возможность параллелизма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Замечание: если число процессоров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; меньше числа строк, но отношение &amp;lt;math&amp;gt;\frac{n}{k} = c&amp;lt;/math&amp;gt; является константой, то каждый процессор вычисляет &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; элементов результирующего вектора, и число ярусов не более чем &amp;lt;math&amp;gt;cn&amp;lt;/math&amp;gt;. Таким образом, предыдущие оценки сложности сохранятся.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6833</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6833"/>
		<updated>2016-10-13T19:50:42Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф &lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычисление &lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как было указано ранее, возможность параллелизма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работает с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). На данном процессоре выполняется &lt;br /&gt;
&amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt; последовательных операций умножения и сложения. Число ярусов для i-ого процессора равно &amp;lt;math&amp;gt; AI_{i+1} - AI_i &amp;lt;/math&amp;gt;. Поскольку изначальная разреженная матрица имеет произвольную структуру, число ярусов на различных процессорах может быть различно. В худшем случае (если в строке все элементы ненулевые) число ярусов будет равно &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Таким образом, для алгоритма умножения разреженной матрицы на плотный вектор в параллельном варианте требуется последовательно выполнить:&lt;br /&gt;
&lt;br /&gt;
* не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений,&lt;br /&gt;
* в каждом из ярусов не более чем &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6801</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6801"/>
		<updated>2016-10-13T19:30:53Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Для того чтобы построить информационный граф &lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычисление &lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Как было указано ранее, возможность параллелизма появляется благодаря независимости вычисления каждого элемента результирующего вектора &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt;. Предположим, что имеется неограниченное число процессоров (теоретически, для максимальной эффективности требуется &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; процессоров). Каждый процессор работатет с одной строкой разреженной матрицы и хранит в памяти только те части массивов &lt;br /&gt;
&amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt;, которые соответствуют данной строке. Вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; хранится в памяти всех процессоров. Таким образом достигается экономия памяти (объем данных для i-ого процессора  &amp;lt;math&amp;gt; 2(AI_{i+1} - AI_i) + n &amp;lt;/math&amp;gt;). &lt;br /&gt;
&lt;br /&gt;
Для алгоритма умножения квадратной матрицы на вектор порядка n в параллельном варианте требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
* по &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений (в каждом из ярусов — &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
Для умножения матрицы размером &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; строк на &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; столбцов на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; в последовательном (наиболее быстром) варианте требуется:&lt;br /&gt;
 &lt;br /&gt;
* по &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; ярусов умножений и сложений (в каждом из ярусов — &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; операций).&lt;br /&gt;
&lt;br /&gt;
При этом использование режима накопления требует совершения умножений и сложений в режиме двойной точности, а в параллельном варианте это означает, что практически все промежуточные вычисления для выполнения алгоритма в режиме накопления должны быть двойной точности. В отличие от последовательного варианта это означает некоторое увеличение требуемой памяти.&lt;br /&gt;
&lt;br /&gt;
При классификации по высоте ЯПФ, таким образом, алгоритм умножения матрицы на вектор относится к алгоритмам &#039;&#039;с линейной сложностью&#039;&#039;. При классификации по ширине ЯПФ его сложность также будет &#039;&#039;линейной&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6790</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6790"/>
		<updated>2016-10-13T19:15:45Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6695</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6695"/>
		<updated>2016-10-13T17:49:14Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром алгоритма является формула умножения разреженной матрицы на плотный вектор:&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
для всех &amp;lt;math&amp;gt;i = 1,n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6693</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6693"/>
		<updated>2016-10-13T17:45:59Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 2 1 3 4 ]&lt;br /&gt;
    IA = [ 0 0 2 3 4 ]&lt;br /&gt;
    JA = [ 0 3 2 1 ]&lt;br /&gt;
домножим ее на вектор&lt;br /&gt;
    x  = [ 5 6 7 8 ]&lt;br /&gt;
получим&lt;br /&gt;
    y[0] = 0&lt;br /&gt;
    y[1] = a[0]*x[0] + a[1]*x[3] = 18&lt;br /&gt;
    y[2] = a[2]*x[2] = 21&lt;br /&gt;
    y[3] = a[3]*x[1] = 24 &lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6685</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6685"/>
		<updated>2016-10-13T17:39:06Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Таким образом, каждый элемент итогового вектора определятся формулой&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
Нетрудно заметить, что общее число операций умножения равно числу элементов &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, то есть числу ненулевых элементов разреженной матрицы.&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 1 2 3 4 ]&lt;br /&gt;
    IA = [ 0 1 2 3 4 ]&lt;br /&gt;
    JA = [ 3 0 2 1 ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор  &amp;lt;math&amp;gt;M*x=y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6675</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6675"/>
		<updated>2016-10-13T17:36:00Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &lt;br /&gt;
&amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_{ik} x_k&amp;lt;/math&amp;gt;, &lt;br /&gt;
то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). Необходимо также знать на какой элемент вектора должен быть домножен данный ненулевой элемент массива, то есть нужен столбцовый индекс каждого элемента &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Для этого используется массив &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;. Подытожив все вышесказанное получим, что каждый элемент итогового вектора определятся формулой&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 1 2 3 4 ]&lt;br /&gt;
    IA = [ 0 1 2 3 4 ]&lt;br /&gt;
    JA = [ 3 0 2 1 ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор  &amp;lt;math&amp;gt;M*x=y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6658</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6658"/>
		<updated>2016-10-13T17:29:05Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = 1}^{n} A_ik x_k&amp;lt;/math&amp;gt;, то в случае разреженной матрицы достаточно выполнять умножения только для ненулевых элементов &amp;lt;math&amp;gt;A_ik&amp;lt;/math&amp;gt;, которые хранятся в массиве &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; в части соответствующей строке &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; (элементы с индексами от &amp;lt;math&amp;gt;IA_i&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;IA_{i+1}&amp;lt;/math&amp;gt;). &lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 1 2 3 4 ]&lt;br /&gt;
    IA = [ 0 1 2 3 4 ]&lt;br /&gt;
    JA = [ 3 0 2 1 ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор  &amp;lt;math&amp;gt;M*x=y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6647</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6647"/>
		<updated>2016-10-13T17:23:11Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^n&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
Если при умножении плотной матрицы на вектор каждый элемент результата определяется по формуле&lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
представляемая в формате CSR &lt;br /&gt;
    A  = [ 1 2 3 4 ]&lt;br /&gt;
    IA = [ 0 1 2 3 4 ]&lt;br /&gt;
    JA = [ 3 0 2 1 ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор  &amp;lt;math&amp;gt;M*x=y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм умножения матрицы на вектор полностью детерминирован и не зависит от порядка хранения элементов принадлежащих одной строке.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6642</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6642"/>
		<updated>2016-10-13T17:18:18Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^{n*1}&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 представляемая в формате CSR &lt;br /&gt;
    A  = [ 1 2 3 4 ]&lt;br /&gt;
    IA = [ 0 1 2 3 4 ]&lt;br /&gt;
    JA = [ 3 0 2 1 ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор  &amp;lt;math&amp;gt;M*x=y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6641</id>
		<title>Участник:Руфина Третьякова/Хранение ненулевых элементов разреженных матриц. Умножение разреженной матрицы на вектор</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:%D0%A0%D1%83%D1%84%D0%B8%D0%BD%D0%B0_%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D0%B0/%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85_%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86._%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D1%8B_%D0%BD%D0%B0_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80&amp;diff=6641"/>
		<updated>2016-10-13T17:17:41Z</updated>

		<summary type="html">&lt;p&gt;Trrufina: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Умножение разреженной матрицы на вектор&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;2(nnz+n)+1&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Авторы статьи: [[Участница:Руфина_Третьякова|Третьякова Р. М.]] (группа 603), [[Участница:Екатерина_Буторина|Буторина Е. В.]] (группа 603)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Разрежённая матрица — это матрица с преимущественно нулевыми элементами. В противном случае, если бо́льшая часть элементов матрицы ненулевые, матрица считается плотной.&lt;br /&gt;
Среди специалистов нет единства в определении того, какое именно количество ненулевых элементов делает матрицу разрежённой. Разные авторы предлагают различные варианты. &lt;br /&gt;
Огромные разрежённые матрицы часто возникают при решении таких задач, как дифференциальное уравнение в частных производных или операции с графами.&lt;br /&gt;
При хранении и преобразовании разрежённых матриц в компьютере бывает полезно, а часто и необходимо, использовать специальные алгоритмы и структуры данных, которые учитывают разрежённую структуру матрицы. Операции и алгоритмы, применяемые для работы с обычными, плотными матрицами, применительно к большим разрежённым матрицам работают относительно медленно и требуют значительных объёмов памяти. Однако разрежённые матрицы могут быть легко сжаты путём записи только своих ненулевых элементов, что снижает требования к компьютерной памяти.&lt;br /&gt;
Сложность операции с разреженными матрицами чаще всего определяется не их размером но числом ненулевых элементов. Далее будет показано, что умножение разреженной матрицы на плотный вектор можно произвести ровно за столько умножений сколько в матрице ненулевых элементов.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Исходные данные:  разреженная матрица &amp;lt;math&amp;gt;M^{n*n}&amp;lt;/math&amp;gt;, вектор &amp;lt;math&amp;gt;x^{n*1}&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Наиболее удобным форматом для вычисления произведения матрицы на вектор является &amp;quot;Compressed Sparse Row&amp;quot; или сокращенно CSR-формат.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим CSR-представление разреженной матрицы: пусть число ненулевых элементов матрицы равно &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;&lt;br /&gt;
CSR-формат представляет матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; в виде 3-х одномерных массивов:&lt;br /&gt;
&lt;br /&gt;
массив &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; содержит ненулевые значения матрицы,&lt;br /&gt;
&amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; - номера столбцов ненулевых элементов., &lt;br /&gt;
&amp;lt;math&amp;gt;IA&amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;- содержит номер с которого начинается описание элементов строки в массивах &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;JA&amp;lt;/math&amp;gt;.&lt;br /&gt;
Этот формат позволяет производить перемножение матрицы &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на вектор &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(nnz)&amp;lt;/math&amp;gt; умножений и сложений. &lt;br /&gt;
&lt;br /&gt;
Например, это разреженная матрица с 4-мя ненулевыми элементами&lt;br /&gt;
:: &amp;lt;math&amp;gt;\begin{pmatrix}&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
2 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 3 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 4 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/math&amp;gt;,&lt;br /&gt;
 представляемая в формате CSR &lt;br /&gt;
    A  = [ 1 2 3 4 ]&lt;br /&gt;
    IA = [ 0 1 2 3 4 ]&lt;br /&gt;
    JA = [ 3 0 2 1 ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Вычисляемые данные: вектор  &amp;lt;math&amp;gt;M*x=y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&lt;br /&gt;
  &#039;&#039;&#039;Входные данные&#039;&#039;&#039;:&lt;br /&gt;
    число строк матрицы &#039;&#039;n&#039;&#039;; &lt;br /&gt;
    разреженная матрица в формате CSR:&lt;br /&gt;
      строчные указатели &#039;&#039;IA&#039;&#039;,&lt;br /&gt;
      столбцовые указатели&#039;&#039;JA&#039;&#039;, &lt;br /&gt;
      ненулевые элементы &#039;&#039;A&#039;&#039;;&lt;br /&gt;
    вектор &#039;&#039;x&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: произведение матрицы на вектор &#039;&#039;y&#039;&#039;.&lt;br /&gt;
  &#039;&#039;&#039;read CSR&#039;&#039;&#039; &#039;&#039;n&#039;&#039;, &#039;&#039;IA&#039;&#039;, &#039;&#039;JA&#039;&#039;, &#039;&#039;A&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;read&#039;&#039;&#039; &#039;&#039;x&#039;&#039;&lt;br /&gt;
  &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;i&#039;&#039; = 1,n:&lt;br /&gt;
    &#039;&#039;&#039;for&#039;&#039;&#039; &#039;&#039;k&#039;&#039; = &#039;&#039;IA(i)&#039;&#039;, &#039;&#039;IA(i+1)-1&#039;&#039;:&lt;br /&gt;
            &#039;&#039;y(i)&#039;&#039; += &#039;&#039;A(k)&#039;&#039;*&#039;&#039;x(JA(k))&#039;&#039;;&lt;br /&gt;
  &#039;&#039;&#039;write&#039;&#039;&#039; &#039;&#039;y&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Метод можно описать следующим образом:&lt;br /&gt;
# привести матрицу &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; к формату CSR&lt;br /&gt;
# для &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt; вычислить &amp;lt;math&amp;gt;y_i&amp;lt;/math&amp;gt; по формуле &amp;lt;math&amp;gt;y_i = \sum_{k = IA_i}^{IA_{i+1}} A_k x_{JA_k}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления матрично-векторного произведения матрицы размера &amp;lt;math&amp;gt;n*n&amp;lt;/math&amp;gt; и вектора размера n в последовательном варианте требуется:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; сложений,&lt;br /&gt;
* &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt; умножений.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для параллельного умножения матрицы на вектор порядка &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; требуется последовательно выполнить следующие ярусы:&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входными данными алгоритма являются:&lt;br /&gt;
# размер разреженной матрицы &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AI &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n+1 &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; AJ &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; A &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; nnz &amp;lt;/math&amp;gt;;&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; x &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммарная размерность входных данных: &amp;lt;math&amp;gt; 2(nnz + n) + 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выходными данными является&lt;br /&gt;
# вектор &amp;lt;math&amp;gt; y &amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Если размерность матрицы &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, число ненулевых элементов &amp;lt;math&amp;gt;nnz&amp;lt;/math&amp;gt;, для вычисления используется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; процессоров тогда: &lt;br /&gt;
&lt;br /&gt;
*Каждый процессор оперирует с &amp;lt;math&amp;gt;\frac{n}{k}&amp;lt;/math&amp;gt; строками, в каждой из которых примерно &amp;lt;math&amp;gt;\frac{nnz}{n}&amp;lt;/math&amp;gt; элементов. Параллельная сложность алгоритма - &amp;lt;math&amp;gt;O(\frac{nnz}{k})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Вычислительная мощность алгоритма (отношение числа операций к суммарному объему входных и выходных данных) - &amp;lt;math&amp;gt;O(\frac{nnz}{2nnz + 3n}) = O(1)&amp;lt;/math&amp;gt; - для последовательного алгоритма; &amp;lt;math&amp;gt;O(\frac{nnz}{n} / (2\frac{nnz}{n} + n)) = O(1) &amp;lt;/math&amp;gt; - для параллельного алгоритма.&lt;br /&gt;
&lt;br /&gt;
При этом алгоритм умножения матрицы на вектор полностью детерминирован. Использование другого порядка выполнения ассоциативных операций в данной версии нами не рассматривается.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная реализация имеется в пакете SPARSKIT [http://w3.pppl.gov/~hammett/work/2006/gmres/SPARSKIT2/BLASSM/matvec.f], Python.Scipy [https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.csr_matrix.html]&lt;br /&gt;
&lt;br /&gt;
Параллельный алгоритм реализован в библиотеке Matlab [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.6692&amp;amp;rep=rep1&amp;amp;type=pdf], Intel MKL [https://software.intel.com/en-us/node/468536#D09FB46A-B404-44CC-94ED-1C434C41B6E1]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] С. Писсанецки. Технология разреженных матриц. Изд. Мир, 1988.&lt;br /&gt;
&lt;br /&gt;
[2] В. В. Воеводин, Вл.В. Воеводин. Параллельные вычисления. – СПб.: БХВ - Петербург, 2002.&lt;/div&gt;</summary>
		<author><name>Trrufina</name></author>
	</entry>
</feed>