Skip to content

Commit c92a66a

Browse files
committed
Особенности реализации вынесены в общий раздел. Не все.
1 parent 47ed20c commit c92a66a

5 files changed

Lines changed: 151 additions & 150 deletions

File tree

book_structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@
314314

315315
> Итоги книги, дальнейшие направления, открытые проблемы.
316316
317-
- Раздел "Об особенностях реализации" — `01_ImplementationFeatures.tex`
317+
- ⚠️ Раздел "Об особенностях реализации" — `01_ImplementationFeatures.tex`
318318
- ❌ Раздел "О смежных областях" — `02_RelatedAreas.tex`
319319
- Свежие работы и обзоры
320320
- ❌ Раздел "О возможных направлениях исследований" — `03_ResearchDirections.tex`

tex/part_01_Prep/chapter_01_LinearAlgebra/07_MatricesAndVectors.tex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ \section{Матрицы и вектора}
218218
\begin{multline*}
219219
K = M \otimes N =
220220
\begin{pmatrix}
221-
(M[0,0] \circ N & \cdots & M[0,n-1] \circ N \\
221+
M[0,0] \circ N & \cdots & M[0,n-1] \circ N \\
222222
\vdots & \ddots & \vdots \\
223223
M[m-1,0] \circ N & \cdots & M[m-1,n-1] \circ N
224224
\end{pmatrix}
@@ -227,6 +227,8 @@ \section{Матрицы и вектора}
227227

228228
%Заметим, что скалярная операция~--- это частный случай произвеления Кронекера: достаточно превратить элемент носителя полугруппы в матрицу размера $1\times 1$.
229229

230+
\mytodo{Использоывать $\boxtimes$ для Кронекера.}
231+
230232
\begin{remark}
231233
\label{rem:KronIsNotCommutative}
232234
Произведение Кронекера не является коммутативным\sidenote{Показать это можно по определению: найти пример, для которого $M \otimes N \neq N \otimes M$.}.

tex/part_03_GraphAnalysis/chapter_12_CFPQ/02_MatrixBased.tex

Lines changed: 1 addition & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -218,136 +218,4 @@
218218
% \end{example}
219219

220220
% Подробнее алгоритм описан в статье Рустама Азимова и Семёна Григорьева~\cite{565CECD7E8F5C6063935B41DB41797AA37D53B04}. Стоит также отметить, что обобщения данного алгоритма для булевых грамматик не существует, хотя и существует частное решение для случая, когда граф не содержит циклов (является DAG-ом), предложенное Екатериной Шеметовой~\cite{Shemetova2019}.
221-
222-
\subsection{Особенности реализации}
223-
224-
Алгоритмы, описанные выше, удобны с точки зрения реализации тем, что могут быть эффективно реализованы с использованием высокопроизводительных библиотек линейной алгебры, которые эксплуатируют возможности параллельных вычислений на современных CPU и GPGPU~\cite{Mishin:2019:ECP:3327964.3328503}.
225-
Это позволяет с минимальными затратами получить эффективную параллельную реализацию алгоритма для решения задачи КС достижимости в графах.
226-
Благодаря этому, хотя асимптотически приведенные алгоритмы имеют большую сложность чем, скажем, алгоритм Хеллингса, в результате эффективного распараллеливания на практике они работают быстрее однопоточных алгоритмов с лучшей сложностью.
227-
228-
Далее рассмотрим некоторые детали, упрощающие реализацию с использованием современных библиотек и аппаратного обеспечения.
229-
230-
Так как множество нетерминалов и правил конечно, то мы можем свести представленный выше алгоритм к булевым матрицам: для каждого нетерминала заведём матрицу, такую что в ячейке стоит 1 тогда и только тогда, когда в исходной матрице в соответствующей ячейке содержится этот нетерминал.
231-
Тогда перемножение пары таких матриц, соответствующих нетерминалам $A$ и $B$, соответствует построению путей, выводимых из нетерминалов, для которых есть правила с правой частью вида $A B$.
232-
233-
\begin{example}
234-
Представим в виде набора булевых матриц следующую матрицу:
235-
\[
236-
T_0 = \begin{pmatrix}
237-
\varnothing & \{A\} & \varnothing & \{B\} \\
238-
\varnothing & \varnothing & \{A\} & \varnothing \\
239-
\{A\} & \varnothing & \varnothing & \varnothing \\
240-
\{B\} & \varnothing & \varnothing & \varnothing \\
241-
\end{pmatrix}
242-
\]
243-
244-
Тогда:
245-
\begin{alignat*}{7}
246-
& &&T_{0\_A} &&= \begin{pmatrix}
247-
0 & 1 & 0 & 0 \\
248-
0 & 0 & 1 & 0 \\
249-
1 & 0 & 0 & 0 \\
250-
0 & 0 & 0 & 0 \\
251-
\end{pmatrix} \ \ \ \ &&T_{0\_B} &&= \begin{pmatrix}
252-
0 & 0 & 0 & 1 \\
253-
0 & 0 & 0 & 0 \\
254-
0 & 0 & 0 & 0 \\
255-
1 & 0 & 0 & 0 \\
256-
\end{pmatrix}
257-
\end{alignat*}
258-
Тогда при наличии правила $S \to A B$ в грамматике получим:
259-
\[
260-
T_{1\_S} =T_{0\_A} \times T_{0\_B} = \begin{pmatrix}
261-
0 & 0 & 0 & 0 \\
262-
0 & 0 & 0 & 0 \\
263-
0 & 0 & 0 & 1 \\
264-
0 & 0 & 0 & 0 \\
265-
\end{pmatrix}
266-
\]
267-
\end{example}
268-
269-
Алгоритм же может быть переформулирован так, как показано в листинге~\ref{lst:cfpq_mtx_bool}.
270-
Такой взгляд на алгоритм позволяет использовать для его реализации существующие высокопроизводительные библиотеки для работы с булевыми матрицами (например M4RI\sidenote{M4RI~--- одна из высокопроизводительных библиотек для работы с логическими матрицами на CPU. Реализует Метод Четырёх Русских. Исходный код библиотеки: \url{https://bitbucket.org/malb/m4ri/src/master/}. Дата посещения: 30.03.2020.}~\cite{DBLP:journals/corr/abs-0811-1714}) или библиотеки для линейной алгебры (например CUSP~\cite{Cusp}).
271-
272-
\begin{algorithm}
273-
\floatname{algorithm}{Listing}
274-
% TODO!!!
275-
%\begin{algorithmic}[1]
276-
%\caption{Context-free path querying algorithm. Boolean matrix version}
277-
%\label{lst:cfpq_mtx_bool}
278-
%\Function{evalCFPQ}{$D=(V,E), G=(N,\Sigma,P)$}
279-
% \State{$n \gets$ |V|}
280-
% \State{$T \gets \{T^{A_i} \mid A_i \in N, T^{A_i}$ is a matrix $n \times n$, $T^{A_i}_{k,l} \gets$ \texttt{false}\} }
281-
% \ForAll{$(i,x,j) \in E$, $A_k \mid A_k \to x \in P$}
282-
% %\Comment{Matrices initialization}
283-
% %\For{$A_k \mid A_k \to x \in P$}
284-
% {$T^{A_k}_{i,j} \gets \texttt{true}$}
285-
% %\EndFor
286-
% \EndFor
287-
% \For{$A_k \mid A_k \to \varepsilon \in P$}
288-
% {$T^{A_k}_{i,i} \gets \texttt{true}$}
289-
% \EndFor
290-
291-
% \While{any matrix in $T$ is changing}
292-
% %\Comment{Transitive closure calculation}
293-
% \For{$A_i \to A_j A_k \in P$}
294-
% { $T^{A_i} \gets T^{A_i} + (T^{A_j} \times T^{A_k})$ }
295-
% \EndFor
296-
% \EndWhile
297-
%\State \Return $T$
298-
%\EndFunction
299-
%\end{algorithmic}
300-
\end{algorithm}
301-
302-
С другой стороны, для запросов, выразимых в терминах грамматик с небольшим количеством нетерминалов, практически может быть выгодно представлять множества нетерминалов в ячейке матрицы в виде битового вектора следующим образом.
303-
Нумеруем все нетерминалы с нуля, в векторе стоит 1 на позиции $i$, если в множестве есть нетерминал с номером $i$.
304-
Таким образом, в каждой ячейке хранится битовый вектор длины $|N|$.
305-
Тогда операция умножения определяется следующим образом:
306-
\[v_1 \times v_2 = \{v \mid \exists (v,v_3) \in P, \textit{append}(v_1, v_2) \& v_3 = v_3\},\] где $\&$~--- побитовое \texttt{``и''}.
307-
308-
Правила надо кодировать соответственно: продукция это пара, где первый элемент~--- битовый вектор длины $|N|$ с единственной единицей в позиции, соответствующей нетерминалу в правой части, а второй элемент~--- вектор длины $2|N|$, с двумя единицами кодирующими первый и второй нетерминалы.
309-
310-
\begin{example}
311-
Пусть $N = \{S, A, B\}$ и в грамматике есть продукция $S \to A B$. Тогда занумеруем нетерминалы $ (S, 0), (A, 1), (B, 2)$. Продукция примет вид $[1, 0, 0] \to [0, 1, 0, 0, 0, 1]$. Матрица $T_0$ примет вид (здесь <<$.$>> означает, что в ячейке стоит $[0,0,0]$):
312-
\[
313-
T_0 = \begin{pmatrix}
314-
. & [0,1,0] & . & [0,0,1] \\
315-
. & . & [0,1,0] & . \\
316-
[0,1,0] & . & . & . \\
317-
[0,0,1] & . & . & . \\
318-
\end{pmatrix}
319-
\]
320-
321-
После выполнения умножения получим:
322-
\[
323-
T_1 = T_0 + T_0 \times T_0 =
324-
\begin{pmatrix}
325-
. & [0,1,0] & . & [0,0,1] \\
326-
. & . & [0,1,0] & . \\
327-
[0,1,0] & . & . & \cellcolor{lightgray}[1,0,0] \\
328-
[0,0,1] & . & . & . \\
329-
\end{pmatrix}
330-
\]
331-
\end{example}
332-
333-
334-
На практике в роли векторов могут выступать беззнаковые целые числа.
335-
Например, 32 бита под ячейки в матрице и 64 бита под правила (или 8 и 16, если позволяет количество нетерминалов в грамматике, или 16 и 32).
336-
Тогда умножение выражается через битовые операции и сравнение, что довольно эффективно с точки зрения вычислений.
337-
338-
Для небольших запросов такой подход к реализации может оказаться быстрее: в данном случае скорость зависит от деталей.
339-
Минус подхода в том, что нет возможности использовать готовые библиотеки линейной алгебры без предварительной модификации.
340-
Только если они не являются параметризуемыми и не позволяют задать собственный тип и собственную операцию умножения и сложения (иными словами, собственное полукольцо).
341-
Такую возможность предусматривает, например, стандарт GraphBLAS\sidenote{GraphBLAS~--- открытый стандарт, описывающий набор примитивов и операций, необходимый для реализации графовых алгоритмов в терминах линейной алгебры. Web-страница проекта: \url{https://github.com/gunrock/graphblast}. Дата доступа: 30.03.2020.} и, соответственно, его реализации, такие как SuiteSparse\sidenote{SuiteSparse~--- это специализированное программное обеспечения для работы с разреженными матрицами, которое включает в себя реализацию GraphBLAS API. Web-страница проекта: \url{http://faculty.cse.tamu.edu/davis/suitesparse.html}. Дата доступа: 30.03.2020.}~\cite{Davis2018Algorithm9S}.
342-
343-
Также стоит заметить, что при работе с реальными графами матрицы, как правило, оказываются разреженными, а значит необходимо использовать соответствующие представления матриц (CRS, покоординатное, Quad Tree~\cite{quadtree}) и библиотеки, работающие с таким представлениями.
344-
345-
Однако даже при использовании разреженных матриц, могут возникнуть проблемы с размером реальных данных и объёмом памяти.
346-
Например, для вычислений на GPGPU лучше всего, когда все нужные для вычисления матрицы помещаются на одну карту.
347-
Тогда можно свести обмен данными между хостом и графическим сопроцессором к минимуму.
348-
Если не помещаются все, то нужно, чтобы помещалась хотя бы тройка непосредственно обрабатываемых матриц (два операнда и результат).
349-
В самом тяжёлом случае в памяти не удаётся разместить даже операнды целиком и тогда приходится прибегать к поблочному умножению матриц.
350-
351-
Отдельной инженерной проблемой является масштабирование алгоритмов на несколько вычислительных узлов, как на несколько CPU, так и на несколько GPGPU.
352-
353-
Важным свойством рассмотренного алгоритма является то, что описанные проблемы с объёмом памяти и масштабированием могут эффективно решаться в рамках библиотек линейной алгебры общего назначения, что избавляет от необходимости создавать специализированные решения для конкретных задач.
221+
\mytodo{Особенности реализации перенесены в раздел~\ref{sec:Conclusion_ImplFeatures} Заключения.}

tex/part_03_GraphAnalysis/chapter_12_CFPQ/03_TensorProduct.tex

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,20 +1244,7 @@ \subsection{Примеры}
12441244
Таким образом, видно, что минимизация представления запроса, в частности, минимизация рекурсивного автомата как конечного автомата над смешанным алфавитом может улучшить производительность выполнения запросов.
12451245
\end{example}
12461246

1247-
\subsection{Особенности реализации}
1248-
1249-
Как и алгоритмы, представленные в разделе~\ref{chpt:MatrixBasedAlgos}, представленный здесь алгоритм оперирует разреженными матрицами, поэтому, к нему применимы все те же соображения, что и к алгоритмам, основанным на произведении матриц. Более того, так как результат тензорного произведения является блочной матрицей, то могут оказаться полезными различные форматы для хранения блочно-разреженных матриц. Вместе с этим, в некоторых случаях матрицу смежности рекурсивного автомата удобнее представлять в классическом, плотном, виде, так как для некоторых запросов её размер мал и накладные расходы на представление в разреженном формате и работе с ним будут больше, чем выигрыш от его использования.
1250-
1251-
1252-
Также заметим, что блочная структура матриц даёт хорошую основу для распределённого умножения матриц при построении транзитивного замыкания.
1253-
1254-
Вместо того, чтобы перезаписывать каждый раз матрицу смежности входного графа $M_2$ можно вычислять только разницу с предыдущим шагом.
1255-
Для этого, правда, потребуется хранить в памяти ещё одну матрицу.
1256-
Поэтому нужно проверять, что вычислительно дешевле: поддерживать разницу и потом каждый раз поэлементно складывать две матрицы или каждый раз вычислять полностью произведение.
1257-
1258-
Заметим, что для решения задачи достижимости нам не нужно накапливать пути вдоль рёбер, как мы это делали в примерах, соответственно, во-первых, можно переопределить тензорное произведение так, чтобы его результатом являлась булева матрица, во-вторых, как следствие первого изменеия, транзитивное замыкание для булевой матрицы можно искать с применением соответствующих оптимизаций.
1259-
1260-
%\section{Вопросы и задачи}
1247+
\mytodo{Особенности реализации перенесены в раздел~\ref{sec:Conclusion_ImplFeatures} Заключения.}%\section{Вопросы и задачи}
12611248
%
12621249
%\begin{enumerate}
12631250
% \item Оценить пространсвенную сложность алгоритма.

0 commit comments

Comments
 (0)