|
218 | 218 | % \end{example} |
219 | 219 |
|
220 | 220 | % Подробнее алгоритм описан в статье Рустама Азимова и Семёна Григорьева~\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} Заключения.} |
0 commit comments