Алгоритм Кока-Янгера-Касами разбора грамматики в НФХ — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Асимптотика)
м (Псевдокод)
Строка 39: Строка 39:
 
     '''for''' i = 1 ... n
 
     '''for''' i = 1 ... n
 
       '''for''' (A <tex>\rightarrow</tex> w[i] <tex>\in</tex> <tex>\Gamma</tex>)
 
       '''for''' (A <tex>\rightarrow</tex> w[i] <tex>\in</tex> <tex>\Gamma</tex>)
           d[A,i,i] = true
+
           d[A][i][i] = true
     '''for''' len = 1 .. n - 1
+
     '''for''' m = 1 .. n - 1
       '''for''' i = 1 .. n - len
+
       '''for''' i = 1 .. n - m
 +
          '''int''' j = i + m
 
           '''for''' (A <tex>\rightarrow</tex> BC <tex>\in</tex> <tex>\Gamma</tex>)
 
           '''for''' (A <tex>\rightarrow</tex> BC <tex>\in</tex> <tex>\Gamma</tex>)
 
             '''for''' k = i .. i + len - 1
 
             '''for''' k = i .. i + len - 1
                 d[A][i][i + len] = d[A][i][i + len] '''or''' d[B][i][k] '''and''' d[C][k + 1][i + len]
+
                 d[A][i][j] = d[A][i][j] '''or''' d[B][i][k] '''and''' d[C][k + 1][j]
 
  '''return''' d[S][1][n]
 
  '''return''' d[S][1][n]
  

Версия 23:22, 4 ноября 2014

Задача:
Пусть дана контекстно-свободная грамматика грамматика [math]\Gamma[/math] в нормальной форме Хомского и слово [math]w \in \Sigma^{*}[/math]. Требуется выяснить, выводится ли это слово в данной грамматике.


Алгоритм

Алгоритм Кока-Янгера-Касами (Cocke — Younger — Kasami algorithm, CYK - алгоритм) - универсальный алгоритм, позволяющий по слову узнать, выводимо ли оно в заданной КС-грамматике в нормальной форме Хомского. Будем решать задачу динамическим программированием. Заведем трехмерный массив d, состоящий из логических значений, и [math]d[A][i][j] = true[/math] тогда и только тогда, когда из нетерминала [math]A[/math] правилами грамматики можно вывести подстроку [math]w[i..j][/math].

Рассмотрим все пары [math]\lbrace \langle j, i \rangle | j-i=m \rbrace[/math], где [math]m[/math] - константа и [math]m \lt n[/math].

Шаг 1. База

[math]m = 0[/math]. В таком случае [math]i = j[/math].

Инициализируем массив для всех нетерминалов, из которых выводится какой-либо символ строки [math]w[/math]. В таком случае:

[math]d[A][i][i] = true[/math], если в грамматике [math]\Gamma[/math] присутствует правило [math]A \rightarrow w[i][/math]. Иначе [math]d[A][i][i] = false[/math].

Шаг 2. Переход

CYK rule 2.jpg

[math]m = j - i[/math].

Значения для всех нетерминалов и пар [math]\lbrace \langle j', i' \rangle | j' - i' \lt m \rbrace[/math] уже вычислены, поэтому [math]d[A][i][j] = \bigvee\limits_{A \rightarrow BC}\bigvee\limits_{k = i}^{j-1} d[B][i][k] \wedge d[C][k+1][j][/math]. То есть, подстроку [math]w[i \dots j][/math] можно вывести из нетерминала [math]A[/math], если существует продукция вида [math]A \rightarrow BC[/math] и такое [math]k[/math], что подстрока [math]w[i \dots k][/math] выводима из [math]B[/math], а подстрока [math]w[k + 1 \dots j][/math] - из [math]C[/math].

Завершение

\После окончания работы значение [math]d[S][1][n][/math] содержит ответ на вопрос, выводима ли данная строка в данной грамматике.

Модификации

Заметим, что если массив будет хранить целые числа, а формулу заменить на [math]d[A][i][j] = \sum\limits_{A \rightarrow BC}\sum\limits_{k = i}^{j-1} d[B,i,k] \cdot d[C,k+1,j][/math], то [math]d[A,i,j][/math] - количество способов получить подстроку [math]w[i \dots j][/math] из нетерминала [math]A[/math].

Пусть [math]P_{A \rightarrow BC}[/math] - стоимость вывода по правилу [math]A \rightarrow BC[/math]. Тогда, если использовать формулу [math]d[A,i,j] = \min\limits_{A \rightarrow BC} \min\limits_{k = i}^{j-1} ( d[B,i,k] + d[C,k+1,j] + P_{A \rightarrow BC} )[/math], то [math]d[A,i,j][/math] - минимальная стоимость вывода подстроки [math]a_i...a_j[/math] из нетерминала [math]A[/math].

Таким образом, задача о выводе в КС-грамматике в нормальной форме Хомского является обобщением задачи динамического программирования на подотрезке.

Псевдокод

boolean CYK(char[] w, list [math]\Gamma[/math], int S)
   int n = length(w)
   boolean d[[math]|\Gamma|[/math]][n][n]
   for i = 1 ... n
      for (A [math]\rightarrow[/math] w[i] [math]\in[/math] [math]\Gamma[/math])
         d[A][i][i] = true
   for m = 1 .. n - 1
      for i = 1 .. n - m
         int j = i + m
         for (A [math]\rightarrow[/math] BC [math]\in[/math] [math]\Gamma[/math])
            for k = i .. i + len - 1
               d[A][i][j] = d[A][i][j] or d[B][i][k] and d[C][k + 1][j]
return d[S][1][n]

Асимптотика

Обработка правил вида [math]A \rightarrow w[i][/math] в шаге 1 выполняется за [math]O(n \cdot |\Gamma|)[/math].

Проход по всем подстрокам выполняется за [math]O(n^2)[/math]. В обработке подстроки присутствует цикл по всем правилам вывода и по всем разбиениям на две подстроки, следовательно обработка работает за [math]O(n \cdot |\Gamma|)[/math]. В итоге получаем конечную сложность [math]O(n^3 \cdot |\Gamma|)[/math].

Следовательно, общее время работы алгоритма - [math]O(n^3 m)[/math]. Кроме того, алгоритму требуется память (на массив [math]d[/math]) объемом [math]O(n^2 \cdot |N|)[/math], где [math]|N|[/math] - количество нетерминалов грамматики.

См. также

Источники информации