<?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=Gkhazeeva</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=Gkhazeeva"/>
	<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/Gkhazeeva"/>
	<updated>2026-10-22T16:45:42Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21436</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21436"/>
		<updated>2016-12-19T20:58:59Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;O(cdn_{iter} + c^2n_{iter})&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;O (M) &amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
На первом ярусе происходит &amp;lt;math&amp;gt; O(cdn_{iter}) &amp;lt;/math&amp;gt; операций, на втором - &amp;lt;math&amp;gt; O(c^2n_{iter}) &amp;lt;/math&amp;gt;, итого высота ЯПФ алгоритма &amp;lt;math&amp;gt; O(cdn_{iter} + c^2n_{iter}) &amp;lt;/math&amp;gt;. Ширина ярусно-параллельной формы алгоритма равна &amp;lt;math&amp;gt; O(M) &amp;lt;/math&amp;gt;. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21435</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21435"/>
		<updated>2016-12-19T20:57:42Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;O(cdn_{iter} + c^2n_{iter})&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;O (M) &amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
На первом ярусе происходит &amp;lt;math&amp;gt; O(cdn_{iter}) &amp;lt;/math&amp;gt; операций, на втором - &amp;lt;math&amp;gt; O(c^2n_{iter}) &amp;lt;/math&amp;gt;, итого высота ЯПФ алгоритма &amp;lt;math&amp;gt; O(cdn_{iter} + c^2n_{iter}) &amp;lt;/math&amp;gt;. Ширина ярусно-параллельной формы алгоритма равна &amp;lt;math&amp;gt; O(M) &amp;lt;/math&amp;gt;. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21434</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21434"/>
		<updated>2016-12-19T20:56:30Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
На первом ярусе происходит &amp;lt;math&amp;gt; O(cdn_{iter}) &amp;lt;/math&amp;gt; операций, на втором - &amp;lt;math&amp;gt; O(c^2n_{iter}) &amp;lt;/math&amp;gt;, итого высота ЯПФ алгоритма &amp;lt;math&amp;gt; O(cdn_{iter} + c^2n_{iter}) &amp;lt;/math&amp;gt;. Ширина ярусно-параллельной формы алгоритма равна &amp;lt;math&amp;gt; O(M) &amp;lt;/math&amp;gt;. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21428</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21428"/>
		<updated>2016-12-19T20:15:34Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;n_{p}&amp;lt;/math&amp;gt; параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21427</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21427"/>
		<updated>2016-12-19T19:56:08Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит из параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21426</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21426"/>
		<updated>2016-12-19T19:55:35Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из параллельных процессов, между которыми равномерно распределены &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21425</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21425"/>
		<updated>2016-12-19T19:51:02Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21424</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21424"/>
		<updated>2016-12-19T19:50:11Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 M)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mn_{iter}  + cMdn_{iter})&amp;lt;/math&amp;gt;. Так как обычно &amp;lt;math&amp;gt; n &amp;gt;&amp;gt; c &amp;lt;/math&amp;gt;, то в этом случае сложность &amp;lt;math&amp;gt;O(c^2 Mn_{iter} )&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21396</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21396"/>
		<updated>2016-12-19T14:56:36Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 Md)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mdn_{iter} )&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2n_{iter} } \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21395</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21395"/>
		<updated>2016-12-19T14:56:16Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 Md)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mdn_{iter} )&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*n_{iter} &amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21394</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21394"/>
		<updated>2016-12-19T14:55:32Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2n_{iter} )&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n_{iter} &amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2n_{iter} &amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 Md)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mdn_{iter} )&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21392</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21392"/>
		<updated>2016-12-19T14:51:49Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; n_{iter} &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 Md)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mdn_{iter} )&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21391</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21391"/>
		<updated>2016-12-19T14:50:55Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 Md)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mdi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21390</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21390"/>
		<updated>2016-12-19T14:49:41Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 Md)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cMd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 Mdi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=21388</id>
		<title>Обсуждение участника:Gkhazeeva</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=21388"/>
		<updated>2016-12-19T14:38:08Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Статья Участник:Gkhazeeva/Нечеткий алгоритм C средних */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Статья [[Участник:Gkhazeeva/Нечеткий алгоритм C средних]] =&lt;br /&gt;
&lt;br /&gt;
* n используется без определения. Что это такое? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 09:27, 19 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* M, d, c — не входят в ширину-высоту формы никаким образом?  [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.1 — что такое «экспоненциальный вес» и зачем он нужен? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:55, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.1 — «проблему объектов» — кластеризации? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.1 — «пока … и предыдущем шаге алгоритма будут отличать» — «пока … не будут отличаться», иначе не согласовано. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* d определён только в 1.9, но используется везде. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.2 — первое использование Xᵢ происходит до его определения. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.2 — какая норма используется? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.4 — «Генерация случайной матрицы размера M на где c, проверка условий» — что имеется ввиду? Смысл не ясен. Матрицы M * c? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — в терминах каких операций измеряется сложность? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — «пересчёт матрицы», если это 1.2.5, от d не зависит, судя по приведённой формуле. Непонятно, откуда взята сложность O(Mc²d). [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — что такое «n»? Возможно, M? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — что такое «i»? В следующем пункте это номер потока. Надо привести обозначения в порядок. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.7 — плохо описано распараллеливание. «M параллельных операций» — нужно количество потоков по числу объектов? Дальше вы совершаете сложение, которое, судя по тексту, выполняется в одном процессе в таком виде имеет сложность O(c*d*M). Так и должно быть? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:55, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.8 — параллельная сложность не зависит от размерности векторов? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.10 — формулировки странные, требует вычитки. «С учётом, если». Опечатки («интерации»). [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.10 — что такое «соотношение форм алгоритма»? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 2.4 — не понятно, что конкретно стоит за цифрами. Их стоит описать в виде формул и определить используемые обозначения. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* Не указан вклад каждого автора [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.2 номера формул следует выравнивать по правому краю, а не прилеплять вплотную к формуле [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Условно исправлено. Форматирование сделано негодными средствами, но неясно, установлены ли средства (https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Equation_numbering), чтобы сделать правильно [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** Пробовал сделать указанными Вами средствами - на этом ресурсе указанные Вами шаблоны не заработали [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
* п. 1.3 состоит из одного предложения и не дает достаточно информации [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.7 приведенный рисунок не является информационным графом: не все дуги ориентированы, имеются циклы [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.9 не приведено оценки объема входных и выходных данных [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* в разделе 2 отсутствуют необходимые пункты, п. 2.2 должен быть 2.7 [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* В списке литературы 1 ссылка - скопированный шаблон без реальной ссылки, 2 ссылка - просто URL без выходных данных источника [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено частично. Ссылка 2 по-прежнему не имеет достаточных выходных данных [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** На сайте, где студентам выдавалось задание ( http://parallel.ru/ss16 ), данный материал предоставлялся в списке источников (номер [8]) в таком же виде, как он указан в данной статье [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
**** Не вижу никакого противоречия с тем, что я написал в замечании [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:47, 7 ноября 2016 (MSK)&lt;br /&gt;
**** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 16:34, 13 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* п. 2.4. Приведен график зависимости эффективности от параметров задачи. Не указано, о какой конкретно эффективности идет речь. [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:29, 17 ноября 2016 (MSK)&lt;br /&gt;
** Была ссылка в справочный раздел с описанием эффективности&lt;br /&gt;
** Подпись под рисункам должна быть самодостаточна, без необходимости разбираться, куда была ссылка и какую ссылку искать. То же касается текста: он должен быть понятен без необходимости ходить по ссылкам, ссылки - средство предоставить дополнительную информацию, для уточнения деталей. [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 16:31, 18 ноября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:24, 21 ноября 2016 (MSK)&lt;br /&gt;
* Необходимо указать характеристики программно-аппаратной платформы (какой компилятор, с какими опциями использовался, какие версии библиотек, на каких узлах проводился запуск и т.д.) [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:24, 21 ноября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 15:24, 22 ноября 2016 (MSK)&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=21387</id>
		<title>Обсуждение участника:Gkhazeeva</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=21387"/>
		<updated>2016-12-19T14:36:55Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Статья Участник:Gkhazeeva/Нечеткий алгоритм C средних */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Статья [[Участник:Gkhazeeva/Нечеткий алгоритм C средних]] =&lt;br /&gt;
&lt;br /&gt;
* n используется без определения. Что это такое? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 09:27, 19 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* M, d, c — не входят в ширину-высоту формы никаким образом?  [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.1 — что такое «экспоненциальный вес» и зачем он нужен? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:55, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.1 — «проблему объектов» — кластеризации? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.1 — «пока … и предыдущем шаге алгоритма будут отличать» — «пока … не будут отличаться», иначе не согласовано. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* d определён только в 1.9, но используется везде. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
** d определен в пункте 1.2 при описании входных параметров Х&lt;br /&gt;
* 1.2 — первое использование Xᵢ происходит до его определения. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.2 — какая норма используется? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.4 — «Генерация случайной матрицы размера M на где c, проверка условий» — что имеется ввиду? Смысл не ясен. Матрицы M * c? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — в терминах каких операций измеряется сложность? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — «пересчёт матрицы», если это 1.2.5, от d не зависит, судя по приведённой формуле. Непонятно, откуда взята сложность O(Mc²d). [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — что такое «n»? Возможно, M? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.6 — что такое «i»? В следующем пункте это номер потока. Надо привести обозначения в порядок. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.7 — плохо описано распараллеливание. «M параллельных операций» — нужно количество потоков по числу объектов? Дальше вы совершаете сложение, которое, судя по тексту, выполняется в одном процессе в таком виде имеет сложность O(c*d*M). Так и должно быть? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:55, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.8 — параллельная сложность не зависит от размерности векторов? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.10 — формулировки странные, требует вычитки. «С учётом, если». Опечатки («интерации»). [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 1.10 — что такое «соотношение форм алгоритма»? [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
* 2.4 — не понятно, что конкретно стоит за цифрами. Их стоит описать в виде формул и определить используемые обозначения. [[Участник:Chalker|Chalker]] ([[Обсуждение участника:Chalker|обсуждение]]) 19:46, 17 декабря 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* Не указан вклад каждого автора [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.2 номера формул следует выравнивать по правому краю, а не прилеплять вплотную к формуле [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Условно исправлено. Форматирование сделано негодными средствами, но неясно, установлены ли средства (https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Equation_numbering), чтобы сделать правильно [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** Пробовал сделать указанными Вами средствами - на этом ресурсе указанные Вами шаблоны не заработали [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
* п. 1.3 состоит из одного предложения и не дает достаточно информации [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.7 приведенный рисунок не является информационным графом: не все дуги ориентированы, имеются циклы [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.9 не приведено оценки объема входных и выходных данных [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* в разделе 2 отсутствуют необходимые пункты, п. 2.2 должен быть 2.7 [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* В списке литературы 1 ссылка - скопированный шаблон без реальной ссылки, 2 ссылка - просто URL без выходных данных источника [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено частично. Ссылка 2 по-прежнему не имеет достаточных выходных данных [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** На сайте, где студентам выдавалось задание ( http://parallel.ru/ss16 ), данный материал предоставлялся в списке источников (номер [8]) в таком же виде, как он указан в данной статье [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
**** Не вижу никакого противоречия с тем, что я написал в замечании [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:47, 7 ноября 2016 (MSK)&lt;br /&gt;
**** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 16:34, 13 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* п. 2.4. Приведен график зависимости эффективности от параметров задачи. Не указано, о какой конкретно эффективности идет речь. [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:29, 17 ноября 2016 (MSK)&lt;br /&gt;
** Была ссылка в справочный раздел с описанием эффективности&lt;br /&gt;
** Подпись под рисункам должна быть самодостаточна, без необходимости разбираться, куда была ссылка и какую ссылку искать. То же касается текста: он должен быть понятен без необходимости ходить по ссылкам, ссылки - средство предоставить дополнительную информацию, для уточнения деталей. [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 16:31, 18 ноября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:24, 21 ноября 2016 (MSK)&lt;br /&gt;
* Необходимо указать характеристики программно-аппаратной платформы (какой компилятор, с какими опциями использовался, какие версии библиотек, на каких узлах проводился запуск и т.д.) [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:24, 21 ноября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 15:24, 22 ноября 2016 (MSK)&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Chalker&amp;diff=21385</id>
		<title>Обсуждение участника:Chalker</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Chalker&amp;diff=21385"/>
		<updated>2016-12-19T14:36:23Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: Новая страница: «d определен в пункте 1.2 при описании входных параметров Х»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;d определен в пункте 1.2 при описании входных параметров Х&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21384</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21384"/>
		<updated>2016-12-19T14:35:08Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам);  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстояние между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21383</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=21383"/>
		<updated>2016-12-19T14:34:34Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров;&amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - параметр, определяющий нечеткость кластеров ( при &amp;lt;math&amp;gt;m = 1&amp;lt;/math&amp;gt; разбиение является четким, с увеличением параметра &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; растет степень &amp;quot;размазанности&amp;quot; объектов по кластерам)  &amp;lt;math&amp;gt;\varepsilon&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: матрица вероятностей принадлежности векторов кластерам.&lt;br /&gt;
&lt;br /&gt;
Краткое описание алгоритма:&lt;br /&gt;
&lt;br /&gt;
* Задать параметры алгоритма.&lt;br /&gt;
&lt;br /&gt;
* Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).&lt;br /&gt;
&lt;br /&gt;
* Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.&lt;br /&gt;
** Рассчитать центры кластеров.&lt;br /&gt;
** Рассчитать расстоение между объектами и центрами кластеров.&lt;br /&gt;
** Пересчитать элементы матрицы нечеткого разбиения.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров, &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов, &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; - набор входных векторов размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В качестве нормы предлагается максимум-норма: &amp;lt;math&amp;gt;||W|| = \max_{i,j} |w_{i,j}|&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом элементы матрицы должны удовлетворять условиям:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M*c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18880</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18880"/>
		<updated>2016-11-21T20:02:05Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18878</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18878"/>
		<updated>2016-11-21T20:01:24Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18874</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18874"/>
		<updated>2016-11-21T19:54:58Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. &lt;br /&gt;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. &lt;br /&gt;
Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились на узлах с процессорами  Intel Xeon X5670 2.93GHz.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18271</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18271"/>
		<updated>2016-11-18T19:41:17Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18269</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18269"/>
		<updated>2016-11-18T19:39:32Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности реализации в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18131</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18131"/>
		<updated>2016-11-18T13:19:13Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=18129</id>
		<title>Обсуждение участника:Gkhazeeva</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=18129"/>
		<updated>2016-11-18T13:18:52Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Статья Нечеткий алгоритм C средних */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Статья [[Нечеткий алгоритм C средних]] =&lt;br /&gt;
* Не указан вклад каждого автора [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.2 номера формул следует выравнивать по правому краю, а не прилеплять вплотную к формуле [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Условно исправлено. Форматирование сделано негодными средствами, но неясно, установлены ли средства (https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Equation_numbering), чтобы сделать правильно [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** Пробовал сделать указанными Вами средствами - на этом ресурсе указанные Вами шаблоны не заработали [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
* п. 1.3 состоит из одного предложения и не дает достаточно информации [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.7 приведенный рисунок не является информационным графом: не все дуги ориентированы, имеются циклы [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.9 не приведено оценки объема входных и выходных данных [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* в разделе 2 отсутствуют необходимые пункты, п. 2.2 должен быть 2.7 [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* В списке литературы 1 ссылка - скопированный шаблон без реальной ссылки, 2 ссылка - просто URL без выходных данных источника [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено частично. Ссылка 2 по-прежнему не имеет достаточных выходных данных [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** На сайте, где студентам выдавалось задание ( http://parallel.ru/ss16 ), данный материал предоставлялся в списке источников (номер [8]) в таком же виде, как он указан в данной статье [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
**** Не вижу никакого противоречия с тем, что я написал в замечании [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:47, 7 ноября 2016 (MSK)&lt;br /&gt;
**** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 16:34, 13 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* п. 2.4. Приведен график зависимости эффективности от параметров задачи. Не указано, о какой конкретно эффективности идет речь. [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:29, 17 ноября 2016 (MSK)&lt;br /&gt;
** Была ссылка в справочный раздел с описанием эффективности&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=18128</id>
		<title>Обсуждение участника:Gkhazeeva</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Gkhazeeva&amp;diff=18128"/>
		<updated>2016-11-18T13:18:37Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Статья Нечеткий алгоритм C средних */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Статья [[Нечеткий алгоритм C средних]] =&lt;br /&gt;
* Не указан вклад каждого автора [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.2 номера формул следует выравнивать по правому краю, а не прилеплять вплотную к формуле [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Условно исправлено. Форматирование сделано негодными средствами, но неясно, установлены ли средства (https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Equation_numbering), чтобы сделать правильно [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** Пробовал сделать указанными Вами средствами - на этом ресурсе указанные Вами шаблоны не заработали [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
* п. 1.3 состоит из одного предложения и не дает достаточно информации [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.7 приведенный рисунок не является информационным графом: не все дуги ориентированы, имеются циклы [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* п. 1.9 не приведено оценки объема входных и выходных данных [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* в разделе 2 отсутствуют необходимые пункты, п. 2.2 должен быть 2.7 [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
* В списке литературы 1 ссылка - скопированный шаблон без реальной ссылки, 2 ссылка - просто URL без выходных данных источника [[Участник:Coctic|Coctic]] ([[Обсуждение участника:Coctic|обсуждение]]) 12:54, 25 октября 2016 (MSK)&lt;br /&gt;
** Исправлено частично. Ссылка 2 по-прежнему не имеет достаточных выходных данных [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:55, 1 ноября 2016 (MSK)&lt;br /&gt;
*** На сайте, где студентам выдавалось задание ( http://parallel.ru/ss16 ), данный материал предоставлялся в списке источников (номер [8]) в таком же виде, как он указан в данной статье [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
**** Не вижу никакого противоречия с тем, что я написал в замечании [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:47, 7 ноября 2016 (MSK)&lt;br /&gt;
**** Исправлено [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 16:34, 13 ноября 2016 (MSK)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
* п. 2.4. Приведен график зависимости эффективности от параметров задачи. Не указано, о какой конкретно эффективности идет речь. [[Участник:Coctic|К. Стефанов]] ([[Обсуждение участника:Coctic|обсуждение]]) 10:29, 17 ноября 2016 (MSK)&lt;br /&gt;
** Был ссылка в справочный раздел с описанием эффективности&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18127</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=18127"/>
		<updated>2016-11-18T13:15:18Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и  [[Глоссарий#Эффективность реализации|эффективности]] выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17771</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17771"/>
		<updated>2016-11-16T18:25:52Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17770</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17770"/>
		<updated>2016-11-16T18:25:35Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration() {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17769</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17769"/>
		<updated>2016-11-16T18:24:36Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
    using namespace std;&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
    int rank, size;&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    double make_iteration()&lt;br /&gt;
    {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
    int FCM(){&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17768</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17768"/>
		<updated>2016-11-16T18:22:57Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
Была использована следующая реализация алгоритма. &lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;mpi.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
    #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;math.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    using namespace std;&lt;br /&gt;
&lt;br /&gt;
    double **x; //input matrix of size (n x x_dim)&lt;br /&gt;
    int n;&lt;br /&gt;
    int x_dim;&lt;br /&gt;
&lt;br /&gt;
    double **centroids; //cluster centroids matrix of size (n_cluster x x_dim)&lt;br /&gt;
    int n_cluster; // number of clusters&lt;br /&gt;
&lt;br /&gt;
    double **w; //probability matrix of size (n x n_cluster)&lt;br /&gt;
    double **dist; //distances matrix of size (n x n_cluster)&lt;br /&gt;
&lt;br /&gt;
    double eps; //max error&lt;br /&gt;
    double m; //parameter of algo&lt;br /&gt;
    int max_iter; // max num of iterations&lt;br /&gt;
&lt;br /&gt;
    double **num;&lt;br /&gt;
    double *den;&lt;br /&gt;
    double *allden;&lt;br /&gt;
    double *err;&lt;br /&gt;
    double *total_err;&lt;br /&gt;
&lt;br /&gt;
    int rank, size;&lt;br /&gt;
&lt;br /&gt;
    double ** generateZerosMatrix(int r, int c){&lt;br /&gt;
        double ** arr = new double* [r];&lt;br /&gt;
&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            arr[i] = new double[c]();&lt;br /&gt;
        }&lt;br /&gt;
        return arr;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    int generate_data()&lt;br /&gt;
    {&lt;br /&gt;
        //generate matrix&lt;br /&gt;
        x = generateZerosMatrix(n, x_dim);&lt;br /&gt;
        centroids = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
        w = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        dist = generateZerosMatrix(n, n_cluster);&lt;br /&gt;
        num = generateZerosMatrix(n_cluster, x_dim);&lt;br /&gt;
&lt;br /&gt;
        //generate vectors&lt;br /&gt;
        den = new double [n_cluster]();&lt;br /&gt;
        allden = new double [n_cluster]();&lt;br /&gt;
&lt;br /&gt;
        //for stopping algorithm&lt;br /&gt;
        err = new double;&lt;br /&gt;
        total_err = new double;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        srand(time(0));&lt;br /&gt;
&lt;br /&gt;
        //initialize w randomly with restrictions&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i){&lt;br /&gt;
            double sum = 0;&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] = rand();&lt;br /&gt;
                sum += w[i][j];&lt;br /&gt;
            }&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                w[i][j] /= sum;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        //initialize x randomly&lt;br /&gt;
        for (int i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                x[i][j] = rand();&lt;br /&gt;
&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    double make_iteration()&lt;br /&gt;
    {&lt;br /&gt;
        // calculate centroids centers&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                double mu = pow(w[i][j], m);&lt;br /&gt;
                den[j] += mu;&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    num[j][k] = mu * x[i][k];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
&lt;br /&gt;
        for (int j=0; j &amp;lt; n_cluster; ++j)&lt;br /&gt;
            MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);&lt;br /&gt;
&lt;br /&gt;
        for (int i = 0; i &amp;lt; n_cluster; ++i)&lt;br /&gt;
            for (int j = 0; j &amp;lt; x_dim; ++j)&lt;br /&gt;
                centroids[i][j] /= allden[i];&lt;br /&gt;
&lt;br /&gt;
        // calculate distances and probabilities, check stop conditions&lt;br /&gt;
        double err = 0.0;&lt;br /&gt;
        for (int i = rank; i &amp;lt; n; i+=size)&lt;br /&gt;
            for (int j = 0; j &amp;lt; n_cluster; ++j){&lt;br /&gt;
                for (int k = 0; k &amp;lt; x_dim; ++k)&lt;br /&gt;
                    dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]);&lt;br /&gt;
&lt;br /&gt;
                double w_prev = w[i][j];&lt;br /&gt;
&lt;br /&gt;
                for (int k = 0; k &amp;lt; n_cluster; ++k)&lt;br /&gt;
                    w[i][j] += dist[i][j] / dist[i][k];&lt;br /&gt;
                w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1));&lt;br /&gt;
                err = fmax(err, abs(w_prev - w[i][j]));&lt;br /&gt;
            }&lt;br /&gt;
        return err;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    int FCM(){&lt;br /&gt;
&lt;br /&gt;
        *total_err = eps+1;&lt;br /&gt;
        int cur_iter = 0;&lt;br /&gt;
        while (cur_iter &amp;lt; max_iter &amp;amp;&amp;amp; *total_err &amp;gt; eps){&lt;br /&gt;
            *err = make_iteration();&lt;br /&gt;
            MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);&lt;br /&gt;
            cur_iter++;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return cur_iter;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void clearMatrix(double ** matr, int r, int c){&lt;br /&gt;
        for (int i = 0; i &amp;lt; r; ++i){&lt;br /&gt;
            delete [] matr[i];&lt;br /&gt;
        }&lt;br /&gt;
        delete [] matr;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    int memory_free(){&lt;br /&gt;
&lt;br /&gt;
        clearMatrix(x, n, x_dim);&lt;br /&gt;
        clearMatrix(centroids, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(w, n_cluster, n);&lt;br /&gt;
        clearMatrix(num, n_cluster, x_dim);&lt;br /&gt;
        clearMatrix(dist, n, n_cluster);&lt;br /&gt;
&lt;br /&gt;
        delete [] den;&lt;br /&gt;
        delete [] allden;&lt;br /&gt;
&lt;br /&gt;
        delete err;&lt;br /&gt;
        delete total_err;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    int main(int argc, char **argv){&lt;br /&gt;
        MPI_Init(&amp;amp;argc, &amp;amp;argv);&lt;br /&gt;
        MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size);&lt;br /&gt;
        MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank);&lt;br /&gt;
&lt;br /&gt;
        int n_repeat = strtol(argv[1], NULL, 10);&lt;br /&gt;
        int nx_min = strtol(argv[2], NULL, 10);&lt;br /&gt;
        int nx_max = strtol(argv[3], NULL, 10);&lt;br /&gt;
        int step = strtol(argv[4], NULL, 10);&lt;br /&gt;
&lt;br /&gt;
        x_dim = strtol(argv[5], NULL, 10);&lt;br /&gt;
        m = strtod(argv[6], NULL);&lt;br /&gt;
        n_cluster = strtol(argv[7], NULL, 10);&lt;br /&gt;
        max_iter = strtol(argv[8], NULL, 10);&lt;br /&gt;
        eps = strtod(argv[9], NULL);&lt;br /&gt;
&lt;br /&gt;
        //for all input matrix sizes&lt;br /&gt;
        for (n = nx_min; n &amp;lt;= nx_max; n += step){&lt;br /&gt;
            double start, finish, time_elapsed_iter=0;&lt;br /&gt;
            int total_iterations = 0;&lt;br /&gt;
            //repeat for getting mean value&lt;br /&gt;
            for (int i = 0; i &amp;lt; n_repeat; ++i) {&lt;br /&gt;
                generate_data();&lt;br /&gt;
                MPI_Barrier(MPI_COMM_WORLD);&lt;br /&gt;
                start = MPI_Wtime();&lt;br /&gt;
                total_iterations += FCM();&lt;br /&gt;
                finish = MPI_Wtime();&lt;br /&gt;
                memory_free();&lt;br /&gt;
                time_elapsed_iter += (finish-start);&lt;br /&gt;
            }&lt;br /&gt;
            time_elapsed_iter /= total_iterations;&lt;br /&gt;
            if (rank == 0) {&lt;br /&gt;
                cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; size &amp;lt;&amp;lt; &amp;quot; &amp;quot; &amp;lt;&amp;lt; time_elapsed_iter &amp;lt;&amp;lt; endl;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        MPI_Finalize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16725</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16725"/>
		<updated>2016-11-13T19:46:25Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16724</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16724"/>
		<updated>2016-11-13T19:45:25Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16723</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16723"/>
		<updated>2016-11-13T19:45:05Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации разложения Холецкого:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16721</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16721"/>
		<updated>2016-11-13T19:41:45Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 0,33%;&lt;br /&gt;
*	максимальная эффективность реализации 9,4%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации разложения Холецкого в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency2.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:&lt;br /&gt;
Построим оценки масштабируемости выбранной реализации разложения Холецкого:&lt;br /&gt;
*	По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается&lt;br /&gt;
*	По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается. &lt;br /&gt;
*	По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16689</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16689"/>
		<updated>2016-11-13T15:59:55Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 128];&lt;br /&gt;
*	размер матрицы [10000 : 80000].&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон [[Глоссарий#Эффективность реализации|эффективности реализации]] алгоритма:&lt;br /&gt;
&lt;br /&gt;
*	минимальная эффективность реализации 3,8%;&lt;br /&gt;
*	максимальная эффективность реализации 83,1%.&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики [[Глоссарий#Производительность|производительности]] и эффективности выбранной реализации разложения Холецкого в зависимости от изменяемых параметров запуска.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16685</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16685"/>
		<updated>2016-11-13T15:49:34Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 1. Параллельная реализация нечеткого алгоритма С-средних. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file: FuzzyCMeansEfficiency.png|thumb|center|700px|Рисунок 2. Параллельная реализация нечеткого алгоритма С-средних. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16683</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16683"/>
		<updated>2016-11-13T15:46:58Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
[[file: FuzzyCMeansPerformance.png |thumb|center|700px|Рисунок 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;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16681</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16681"/>
		<updated>2016-11-13T15:45:07Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Coctic}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
[[file:FuzzyCMeansPerformance.png|thumb|center|700px|Рисунок 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;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16376</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16376"/>
		<updated>2016-11-11T10:11:48Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 3&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15288</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15288"/>
		<updated>2016-10-31T19:46:41Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 6&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15286</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15286"/>
		<updated>2016-10-31T19:45:00Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt;, [количество наблюдений * количество кластеров]&lt;br /&gt;
| pf_height        = &amp;lt;math&amp;gt;2i&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]] ([[#Вычислительное ядро алгоритма|1.3]]; [[#Схема реализации последовательного алгоритма|1.5]]; [[#Последовательная сложность алгоритма|1.6]]; [[#Информационный граф|1.7]]; [[#Масштабируемость алгоритма и его реализации|2.4]]; [[#Существующие реализации алгоритма|2.7]]), [[Участник:Yushin|Павел Юшин]] ([[#Общее описание алгоритма|1.1]]; [[#Математическое описание алгоритма|1.2]]; [[#Макроструктура алгоритма|1.4]]; [[#Ресурс параллелизма алгоритма|1.8]]; [[#Входные и выходные данные алгоритма|1.9]]; [[#Свойства алгоритма|1.10]])&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;[http://www.tandfonline.com/doi/abs/10.1080/01969727308546046 | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57]&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf | Нейский И.М. Классификация и сравнение методов кластеризации.]&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются следующие пункты:&lt;br /&gt;
&lt;br /&gt;
* Поиск &amp;lt;math&amp;gt;V_j&amp;lt;/math&amp;gt; - расчет центроидов (пункт 3 алгоритма)&lt;br /&gt;
* Нахождение &amp;lt;math&amp;gt;D_{ij}&amp;lt;/math&amp;gt; - расстояний между объектами (пункт 4 алгоритма)&lt;br /&gt;
* Пересчет &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; - элементов матрицы разбиения (пункт 5 алгоритма)&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 6&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme3.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Параллельная сложность алгоритма: &amp;lt;math&amp;gt;M*c^2*i&amp;lt;/math&amp;gt;. Такая сложность получается за счет распараллеливания на каждом ярусе &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; операций. Иерархическая структура параллелизма подробно описана в [[#Информационный граф|п.1.7]].&lt;br /&gt;
&lt;br /&gt;
В алгоритме не возникает скошенного параллелизма.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Объем входных данных: &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt; , [количество наблюдений * размерность].&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Объем выходных данных: &amp;lt;math&amp;gt;M*c&amp;lt;/math&amp;gt; , [количество наблюдений * количество кластеров].&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
==Особенности реализации последовательного алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Локальность данных и вычислений==&lt;br /&gt;
&lt;br /&gt;
==Возможные способы и особенности параллельной реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
==Динамические характеристики и эффективность реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
==Выводы для классов архитектур==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=8027</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=8027"/>
		<updated>2016-10-14T19:23:45Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 6&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;{xz} \over {xz}&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=8025</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=8025"/>
		<updated>2016-10-14T19:23:17Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Первый ярус&#039;&#039;&#039; состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Второй ярус&#039;&#039;&#039; состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 6&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;{xz} \over {xz}&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=8023</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=8023"/>
		<updated>2016-10-14T19:22:40Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(Mdc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;M*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;M*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
Информационный граф представлен на рисунке ниже.&lt;br /&gt;
Первый ярус состоит из &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 1, 2, совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз для каждого кластера. &lt;br /&gt;
&#039;&#039;&#039;Операция 1&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 2&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^m*X_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем вектор размера &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; и матрицу размера &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; x &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;. &lt;br /&gt;
Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.&lt;br /&gt;
&lt;br /&gt;
Второй ярус состоит их &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; параллельных операций 3, 4, 5 также совершаемых в цикле &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; раз.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 4&#039;&#039;&#039;: обновление значения &amp;lt;math&amp;gt;w_{ij}&amp;lt;/math&amp;gt; по указанной в разделе 1.2 в пункте 5 формуле.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 5&#039;&#039;&#039;: &amp;lt;math&amp;gt;maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Операция 6&#039;&#039;&#039;: &amp;lt;math&amp;gt;w_{ij}^{prev} = w_{ij}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; - номер итерации в цикле, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - номер параллельной ветви.&lt;br /&gt;
&lt;br /&gt;
На выходе из каждой ветки получаем число &amp;lt;math&amp;gt;maximum&amp;lt;/math&amp;gt;. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[File:Scheme.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Входные данные алгоритма: набор векторов &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i = 1,...,M&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - количество векторов.&lt;br /&gt;
* Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
* Соотношение последовательной и параллельной формы алгоритма: &amp;lt;math&amp;gt;{xz} \over {xz}&amp;lt;/math&amp;gt;&lt;br /&gt;
* Вычислительная мощность: &amp;lt;math&amp;gt;{dc^2i} \over {c+d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.&lt;br /&gt;
* Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированны.&lt;br /&gt;
* Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.&lt;br /&gt;
* Степень исхода вершины информационного графа ( для одной интерации): 2 (3 - с учетом, если выходные данные пошли на следующую итерацию).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма = &lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
==Существующие реализации алгоритма==&lt;br /&gt;
&lt;br /&gt;
* Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf&lt;br /&gt;
* Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6831</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6831"/>
		<updated>2016-10-13T19:49:17Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(ndc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;n*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * |X_i|} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;с; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой расчет центроидов, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, пересчета матрицы и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6825</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6825"/>
		<updated>2016-10-13T19:45:35Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(ndc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;n*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * |X_i|} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;C; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой расчет центроидов, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, пересчета матрицы и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6824</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6824"/>
		<updated>2016-10-13T19:45:15Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(ndc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;n*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * |X_i|} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&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;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;C; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }&lt;br /&gt;
               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой расчет центроидов, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, пересчета матрицы и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6815</id>
		<title>Участник:Gkhazeeva/Нечеткий алгоритм C средних</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:Gkhazeeva/%D0%9D%D0%B5%D1%87%D0%B5%D1%82%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_C_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=6815"/>
		<updated>2016-10-13T19:41:35Z</updated>

		<summary type="html">&lt;p&gt;Gkhazeeva: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Нечеткий алгоритм C средних&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(ndc^2i)&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций&lt;br /&gt;
| input_data         = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;, [количество наблюдений * размерность]&lt;br /&gt;
| output_data          = &amp;lt;math&amp;gt;n*c&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;
}}&lt;br /&gt;
&lt;br /&gt;
Авторы : [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 &amp;lt;ref&amp;gt;{{Cite journal|last=Dunn|first=J. C.|date=1973-01-01|title=A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters|url=http://dx.doi.org/10.1080/01969727308546046|journal=Journal of Cybernetics|volume=3|issue=3|pages=32–57|doi=10.1080/01969727308546046|issn=0022-0280}}&amp;lt;/ref&amp;gt;. Нечеткое разбиение позволяет просто решить проблему объектов, расположенных на границе двух кластеров - им назначают степени принадлежностей равные 0.5.&lt;br /&gt;
&lt;br /&gt;
Входные данные алгоритма: набор векторов, которые следует кластеризовать.&lt;br /&gt;
&lt;br /&gt;
Параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - экспоненциальный вес; &amp;lt;math&amp;gt;\varepsilon&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;
== Математическое описание алгоритма &amp;lt;ref&amp;gt;http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt; W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c&amp;lt;/math&amp;gt; - матрица разбиения, где &amp;lt;math&amp;gt;w_{i,j}&amp;lt;/math&amp;gt; - степень принадлежности объекта &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; к кластеру &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;c&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;
* &amp;lt;math&amp;gt;\sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;0 &amp;lt; \sum_{i = 1}^M w_{ij} &amp;lt; M, j = 1, ..., c&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда алгоритм принимает следующий вид:&lt;br /&gt;
&lt;br /&gt;
1) Задаем параметры алгоритма: &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; - количество кластеров; &amp;lt;math&amp;gt;m &amp;gt;= 1&amp;lt;/math&amp;gt; - экспоненциальный вес, определяющий нечеткость кластеров; &amp;lt;math&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/math&amp;gt; - параметр останова алгоритма.&lt;br /&gt;
&lt;br /&gt;
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий &amp;lt;math&amp;gt;(1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;(2)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) Рассчитываем центроиды (центры кластеров): &amp;lt;math&amp;gt;V_j = {{\sum_{i=1}^M w_{ij}^m * |X_i|} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Рассчитываем расстояния между объектами &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и центроидами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Пересчет элементов матрицы разбиения:&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} &amp;gt;0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
при &amp;lt;math&amp;gt;D_{ij} =0&amp;lt;/math&amp;gt; : &amp;lt;math&amp;gt;w_{ij} = \delta_{ij}, j = 1,...,c&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\delta_{ij}&amp;lt;/math&amp;gt; - символ Кронекера&lt;br /&gt;
&lt;br /&gt;
6) Если &amp;lt;math&amp;gt;|| F - F^{*} || &amp;lt; \varepsilon &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;F^{*}&amp;lt;/math&amp;gt; - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.&lt;br /&gt;
&lt;br /&gt;
7) Конец.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма являются пункты (3), (4), (5) - расчет центроидов, вычисление расстояний и пересчет элементов матрицы соответственно&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
Основные шаги при реализации алгоритма&lt;br /&gt;
*	Генерация случайной матрицы размера &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; на где &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;, проверка условий&lt;br /&gt;
*	Расчет центроидов – по сути, скалярное произведение с нормировкой&lt;br /&gt;
*	Расчет расстояний – в общепринятом случае является скалярным произведением&lt;br /&gt;
*	Пересчет матрицы – по сути, скалярное произведение&lt;br /&gt;
*	Проверка условий останова – вычисление нормы&lt;br /&gt;
&lt;br /&gt;
    float ** FuzzyCMeans (float** X, c, m, eps){&lt;br /&gt;
        n = X.size();&lt;br /&gt;
        r = X[0].size();&lt;br /&gt;
&lt;br /&gt;
        centers = generateZeroFill(c, r)&lt;br /&gt;
        Wprev = genetateRandFill(n, c);&lt;br /&gt;
        W = Wprev;&lt;br /&gt;
&lt;br /&gt;
        while (true){&lt;br /&gt;
            // обновляем центры кластеров &lt;br /&gt;
            for (int i=0; i&amp;lt;c; i++){&lt;br /&gt;
                float * num = new float []();&lt;br /&gt;
                float den = 0;&lt;br /&gt;
                for (int j=0; j&amp;lt;n; j++){&lt;br /&gt;
                    num += pow(W[j][i], m) * X[j];&lt;br /&gt;
                    den+=pow(W[j][i], m);&lt;br /&gt;
                }&lt;br /&gt;
                centers[i] = num / den;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            //обновляем вероятности W и считаем расстояние между матрицами W и Wprev&lt;br /&gt;
            float max_diff = 0;&lt;br /&gt;
            for (int i=0; i&amp;lt;n; i++)&lt;br /&gt;
                for (int j=0; j&amp;lt;c; j++){&lt;br /&gt;
                    total = 0;&lt;br /&gt;
                    for (int m=0; m&amp;lt;C; m++)&lt;br /&gt;
                        total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1));&lt;br /&gt;
                    W[i][j] = 1/total;&lt;br /&gt;
                    max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff);&lt;br /&gt;
                    Wprev[i][j] = W[i][j];&lt;br /&gt;
               }&lt;br /&gt;
               &lt;br /&gt;
           if (max_diff &amp;lt; eps):                &lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        return W;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество. Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой расчет центроидов, сложность которого &amp;lt;math&amp;gt;O(c^2 nd)&amp;lt;/math&amp;gt; (по сравнению со сложностью &amp;lt;math&amp;gt;O(cnd)&amp;lt;/math&amp;gt; расчета расстояний, пересчета матрицы и проверки условия останова). Итого общая сложность алгоритма &amp;lt;math&amp;gt;O(c^2 ndi)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Gkhazeeva</name></author>
	</entry>
</feed>