Минимизация ДКА, алгоритм за O(n^2) с построением пар различимых состояний — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м (Псевдокод)
м (Псевдокод)
Строка 42: Строка 42:
 
     <font color="green">// Шаг 3</font>
 
     <font color="green">// Шаг 3</font>
 
     '''for''' i = 0 .. n - 1
 
     '''for''' i = 0 .. n - 1
       '''for''' j = i + 1 .. n - 1
+
       '''for''' j = 0 .. n - 1
 
           '''if''' '''not''' marked[i][j] '''and''' isTerminal[i] '''and''' '''not''' isTerminal[j] '''and''' i != j
 
           '''if''' '''not''' marked[i][j] '''and''' isTerminal[i] '''and''' '''not''' isTerminal[j] '''and''' i != j
 
             marked[i][j] = marked[j][i] = true
 
             marked[i][j] = marked[j][i] = true

Версия 01:00, 4 ноября 2014

Задача:
Пусть дан автомат [math]\mathcal{A}[/math]. Требуется построить автомат [math]\mathcal{A}_{min}[/math] с наименьшим количеством состояний, распознающий тот же язык, что и [math]\mathcal{A}[/math].


Алгоритм

Описание

Основная идея алгоритма заключается в том, чтобы разбить состояния на классы эквивалентности — они и будут состояниями минимизированного автомата.

Для реализации алгоритма нам потребуются очередь [math]Q[/math] и таблица [math]marked[/math] размером [math]n \times n[/math], где [math]n[/math] — количество состояний автомата. Будем помечать в таблице пары неэквивалентных состояний и класть их в очередь.

  • Удобно будем добавить в исходный автомат вершину [math]0[/math], в которую будут вести по умолчанию все переходы по всем символам, которых ещё не было в исходном автомате. Теперь стартовое состояние будет иметь номер [math]1[/math].
  • Шаг 1. Построим множество [math]\delta^{-1}[/math], в котором будем хранить списки обратных ребер.
  • Шаг 2. Найдем все достижимые состояния из стартового. Например, с помощью обхода в глубину.
  • Шаг 3. Добавим в очередь [math]Q[/math] пары состояний, различимых строкой [math] \varepsilon [/math], и пометим их в таблице.
  • Шаг 4. Для каждой непомеченной пары [math] \langle u, v \rangle [/math] нужно проверить, что [math]\mathcal {9} c \in \Sigma[/math] такой, что пара [math]\langle \delta(u, c), \delta(v, c) \rangle[/math] помечена. Тогда мы можем пометить пару [math] \langle u, v \rangle [/math].
Пока [math]Q[/math] не станет пуста, будем делать следующее:
1. Извлечем пару [math] \langle u, v \rangle [/math] из [math]Q[/math].
2. Для каждого символа [math]c \in \Sigma[/math] перебираем пары состояний [math]\langle \delta^{-1}(u, c), \delta^{-1}(v,c) \rangle[/math]. Если находим ещё непомеченную пару, то помечаем её в таблице и кладем в очередь.
В момент опустошения очереди пары состояний, не помеченные в таблице, являются парами эквивалентных состояний.
  • Шаг 5. За один проход по таблице разбиваем пары эквивалентных состояний на классы эквивалентности.
  • Шаг 6. За один проход по списку классов эквивалентности выделяем список новых состояний и переходов между ними.

Стартовым состоянием полученного автомата будет состояние, соответствующее классу эквивалентности, содержащему стартовое состояние исходного автомата.

Терминальными состояниями полученного автомата будут состояния, соответствующие классам эквивалентности, содержащим терминальные состояния исходного автомата.

Корректность

Пусть в результате применения данного алгоритма к автомату [math]A[/math] мы получили автомат [math]\mathcal{A}_{min}[/math]. Докажем, что этот автомат минимальный и единственный с точностью до изоморфизма.

Пусть существует автомат [math]\mathcal{A}'[/math], эквивалентный [math]\mathcal{A}[/math], но с числом состояний меньшим, чем в [math]\mathcal{A}_{min}[/math]. Стартовые состояния [math]s \in \mathcal{A}_{min}[/math] и [math]s' \in \mathcal{A}'[/math] эквивалентны, так как [math]\mathcal{A}_{min}[/math] и [math]\mathcal{A}'[/math] допускают один и тот же язык. Рассмотрим строку [math]\alpha = a_1a_2...a_{k}[/math], где [math]a_{i} \in \Sigma[/math], такую, что [math] \langle s, \alpha \rangle \vdash^* \langle u, \varepsilon \rangle [/math], [math] \langle s', \alpha \rangle \vdash^* \langle u', \varepsilon \rangle [/math]. Пусть [math]\langle s, a_1 \rangle \vdash^* \langle l, \varepsilon \rangle [/math] и [math]\langle s', a_1 \rangle \vdash^* \langle l', \varepsilon \rangle [/math]. Так как [math]s[/math] и [math]s'[/math] эквивалентны, то [math]l[/math] и [math]l'[/math] эквивалентны. Аналогично для всех [math]a_{i}[/math]. В итоге получим, что [math]u[/math] эквивалентно [math]u'[/math]. Значит, для каждого состояния из [math]\mathcal{A}_{min}[/math] существует эквивалентное состояние из [math]\mathcal{A}'[/math].

Состояний в [math]A'[/math] меньше, чем в [math]\mathcal{A}_{min}[/math], значит двум состояниям из [math]\mathcal{A}_{min}[/math] эквивалентно одно состояние из [math]\mathcal{A}'[/math]. Тогда эти два состояния эквивалентны, но автомат [math]\mathcal{A}_{min}[/math] построен так, что в нем нет эквивалентных состояний. Противоречие.

Так как каждому состоянию из [math]\mathcal{A}_{min}[/math] эквивалентно состояние из [math]\mathcal{A}'[/math], то автоматы [math]\mathcal{A}_{min}[/math] и [math]\mathcal{A}'[/math] изоморфны.

Псевдокод

Функция для построения таблицы неэквивалентности.

boolean[][] buildTable(int n, boolean[] isTerminal, vector[][] [math]\delta^{-1}[/math]):
   queue Q
   boolean marked[n][n]
   // Шаг 3
   for i = 0 .. n - 1
      for j = 0 .. n - 1
         if not marked[i][j] and isTerminal[i] and not isTerminal[j] and i != j
            marked[i][j] = marked[j][i] = true
            Q.push([math]\langle i, j \rangle[/math])

   // Шаг 4
   while not Q.isEmpty()
      [math]\langle u, v \rangle[/math] = Q.poll()
      for c [math]\in[/math] [math]\Sigma[/math]
         list rr = [math]\delta^{-1}[/math][u][c]
         list ss = [math]\delta^{-1}[/math][v][c]	
         for i = 0 .. length(rr) - 1
            int r = rr[i]
            for j = 0 .. length(ss) - 1
               int s = ss[j]
               if not marked[r][s]
                  marked[r][s] = marked[s][r] = true
                  Q.push([math]\langle r, s \rangle[/math])
   return marked

Основная функция алгоритма.

function minimization(int n, boolean[] isTerminal, int[][] [math]\delta[/math]):
   // Шаг 1
   vector[][] [math]\delta^{-1}[/math] = buildReverseEdges(n, [math]\delta[/math]) // Cтроим список обратных ребер.
   // Шаг 2
   boolean reachable[n]
   checkReachability(1, reachable) // Cтроим таблицу достижимости состояний.
   // Шаги 3 и 4
   boolean[][] marked = buildTable(n, isTerminal, [math]\delta^{-1}[/math])
   // Шаг 5
   int[] component[n] // По позиции i будем хранить номер компоненты эквивалентности для i-ого состояния.
   fill(component, -1)
   list classes // По позиции i будем хранить представителя i-ой компоненты эквивалентности.
   for i = 0 .. n - 1
      if not table[0][i]
         component[i] = 0
	
   int components_count = 0
   for i = 1 .. n - 1
      if not visited[i]
         continue
      if component[i] == -1
         components_count++
         component[i] = components_count
         classes.add(i)
         for j = i + 1 .. n - 1
            if not table[i][j]
               component[j] = components_count
   // Шаг 6
   buildDFA(classes, component) // Строим по классам эквивалентности требуемый автомат.

Асимптотика

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

Пример работы

Минимизируем данный автомат:

Dka.png

Шаг 1

Строим [math]\delta^{-1}[/math]. Например, [math]\delta^{-1}(F, 1) = \{C, D, G, F\}[/math].

Шаг 2

Построили массив достижимости состояний из стартового.

0 A B C D E F G H
true true true true false true true true true

Шаг 3

Инициализировали таблицу.

0 A B C D E F G H
0 marked marked
A marked marked
B marked marked
C marked marked
D marked marked
E marked marked
F marked marked marked marked marked marked marked
G marked marked marked marked marked marked marked
H marked marked

Шаг 4

Вычислили таблицу.

0 A B C D E F G H
0 marked marked marked marked marked marked marked marked
A marked marked marked marked marked marked marked
B marked marked marked marked marked marked marked
C marked marked marked marked marked marked marked
D marked marked marked marked marked marked marked
E marked marked marked marked marked marked marked marked
F marked marked marked marked marked marked marked
G marked marked marked marked marked marked marked
H marked marked marked marked marked marked marked marked

Шаг 5

Из таблицы видно, что классы эквивалентных состояний это [math] \mathcal {f} A, B \mathcal {g}, \mathcal {f} C, D \mathcal {g}, \mathcal {f} F, G \mathcal {g}, \mathcal {f} E \mathcal {g}, \mathcal {f} H \mathcal {g} [/math].

Шаг 6

Итого получили такой автомат:

DkaMin.png

См. также

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