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

Материал из Викиконспекты
Перейти к: навигация, поиск
м (Псевдокод)
(Псевдокод)
Строка 34: Строка 34:
 
Функция для построения списка обратных ребер.
 
Функция для построения списка обратных ребер.
 
  '''vector'''[][] buildReverseEdges('''int''' n, '''int'''[][] <tex>\delta</tex>):
 
  '''vector'''[][] buildReverseEdges('''int''' n, '''int'''[][] <tex>\delta</tex>):
 +
    '''int''' <tex>\delta^{-1}</tex>[n][n]
 
     '''for''' i = 0 .. n - 1
 
     '''for''' i = 0 .. n - 1
 
       '''for''' c <tex>\in</tex> <tex>\Sigma</tex>
 
       '''for''' c <tex>\in</tex> <tex>\Sigma</tex>
 
           <tex>\delta^{-1}</tex>[<tex>\delta</tex>[i][c]][c].add(i)
 
           <tex>\delta^{-1}</tex>[<tex>\delta</tex>[i][c]][c].add(i)
 +
    '''return''' <tex>\delta^{-1}</tex>
  
 
Функция для проверки достижимости состояний.
 
Функция для проверки достижимости состояний.
Строка 67: Строка 69:
 
                   marked[r][s] = marked[s][r] = true
 
                   marked[r][s] = marked[s][r] = true
 
                   Q.push(<tex>\langle r, s \rangle</tex>)
 
                   Q.push(<tex>\langle r, s \rangle</tex>)
 +
 +
Основная функция алгоритма.  
 +
'''function''' minimization('''int''' n, '''boolean'''[] isTerminal, '''int'''[][] <tex>\delta</tex>):
 +
    <font color="green">// Шаг 1</font>
 +
    '''int'''[][] <tex>\delta^{-1}</tex> = buildReverseEdges(n, <tex>\delta</tex>)
 +
    <font color="green">// Шаг 2</font>
 +
    '''boolean''' reachable[n]
 +
    checkReachability(1, reachable)
 +
    <font color="green">// Шаг 3</font>
 +
    '''queue''' Q
 +
    '''boolean''' marked[n][n]
 +
    initTable(n, isTerminal, Q, marked)
 +
    <font color="green">// Шаг 4</font>
 +
    computeTable(n, <tex>\delta^{-1}</tex>, Q, marked)
 +
    <font color="green">// Шаг 5</font>
 +
    '''int'''[] component[n] <font color="green">// По позиции i будем хранить номер компоненты эквивалентности для i-ого состояния.</font>
 +
    fill(component, -1)
 +
    '''list''' classes <font color="green">// По позиции i будем хранить представителя i-ой компоненты эквивалентности.</font>
 +
    '''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
 +
    <font color="green">// Шаг 6</font>
 +
    '''for''' i = 0 .. length(classes) - 1
 +
      '''int''' u = component[classes[i]]
 +
      '''for''' c <tex>\in</tex> <tex>\Sigma</tex>
 +
          if reachable[<tex>\delta</tex>[classes[i]][c]] '''and''' component[<tex>\delta</tex>[classes[i]][c]] != 0
 +
            int v = component[<tex>\delta</tex>[classes[i]][c]]
 +
            output(u ->[c]-> v) <font color="green">// Ребро из u в v по символу c</font>
  
 
==Асимптотики==
 
==Асимптотики==

Версия 20:19, 3 ноября 2014

Постановка задачи

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

Алгоритм

Описание

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

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

Будем помечать в таблице пары неэквивалентных состояний и класть их в очередь.

Изначально добавим в очередь [math]Q[/math] пары состояний, различимых строкой [math] \varepsilon [/math], и пометим их в таблице. Пока [math]Q[/math] не станет пуста, будем делать следующее:

  1. Извлечем пару [math] \langle u, v \rangle [/math] из [math]Q[/math].
  2. Отметим в таблице и добавим в очередь [math]Q[/math] все пары [math] \langle t, k \rangle [/math] такие, что [math] \mathcal {9} c \in \Sigma, \langle t, c \rangle \vdash \langle u, \varepsilon \rangle, \langle k, c \rangle \vdash \langle v, \varepsilon \rangle [/math], и пара [math] \langle t, k \rangle[/math] не отмечена в таблице.

В момент опустошения очереди пары состояний, не помеченные в таблице, являются парами эквивалентных состояний. За один проход по таблице разбиваем пары эквивалентных состояний на классы эквивалентности.

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

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

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

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

Пусть существует автомат [math]A'[/math], эквивалентный [math]A[/math], но с числом состояний меньшим, чем в [math]A_{min}[/math]. Стартовые состояния [math]s \in A_{min}[/math] и [math]s' \in A'[/math] эквивалентны, так как [math]A_{min}[/math] и [math]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]A_{min}[/math] существует эквивалентное состояние из [math]A'[/math].

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

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

Псевдокод

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

vector[][] buildReverseEdges(int n, int[][] [math]\delta[/math]):
   int [math]\delta^{-1}[/math][n][n]
   for i = 0 .. n - 1
      for c [math]\in[/math] [math]\Sigma[/math]
         [math]\delta^{-1}[/math][[math]\delta[/math][i][c]][c].add(i)
   return [math]\delta^{-1}[/math]

Функция для проверки достижимости состояний.

function checkReachability(int u, boolean[] visited):
   visited[u] = true;
   for c [math]\in[/math] [math]\Sigma[/math]
      if not visited[[math]\delta[/math][u][c]]
         checkReachability([math]\delta[/math][u][c], visited)

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

function initTable(int n, boolean[] isTerminal, queue Q, boolean[][] marked):
   for i = 0 .. n - 1
      for j = 0 .. n - 1
         if not marked[i][j] and isTerminals[i] and not isTerminals[j] and i != j
            marked[i][j] = marked[j][i] = true
            Q.push([math]\langle i, j \rangle[/math])

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

function computeTable(int n, int[][] [math]\delta^{-1}[/math], queue Q, boolean[][] marked):
   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])

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

function minimization(int n, boolean[] isTerminal, int[][] [math]\delta[/math]):
   // Шаг 1
   int[][] [math]\delta^{-1}[/math] = buildReverseEdges(n, [math]\delta[/math])
   // Шаг 2
   boolean reachable[n]
   checkReachability(1, reachable) 
   // Шаг 3
   queue Q
   boolean marked[n][n]
   initTable(n, isTerminal, Q, marked)
   // Шаг 4
   computeTable(n, [math]\delta^{-1}[/math], Q, marked)
   // Шаг 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
   for i = 0 .. length(classes) - 1
      int u = component[classes[i]]
      for c [math]\in[/math] [math]\Sigma[/math]
         if reachable[[math]\delta[/math][classes[i]][c]] and component[[math]\delta[/math][classes[i]][c]] != 0
            int v = component[[math]\delta[/math][classes[i]][c]]
            output(u ->[c]-> v) // Ребро из u в v по символу c

Асимптотики

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

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

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

Dka.png


Будем рассматривать только нижний треугольник таблицы пар различимых состояний.

Отметили состояния, различающиеся строкой [math]\varepsilon[/math]:

B
C
D
E
F x x x x x
G x x x x x
H x x
A B C D E F G


На момент опустошения очереди:

B
C x x
D x x
E x x x x
F x x x x x
G x x x x x
H x x x x x x x
A B C D E F G

Из таблицы видно, что классы эквивалентных состояний это [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].

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

DkaMin.png

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

  • Хопкрофт Д., Мотвани Р., Ульман Д. Введение в теорию автоматов, языков и вычислений, 2-е издание. Пер. с англ. — М.: Издательский дом «Вильямс», 2002. — С. 171 - 182. — ISBN 5-8459-0261-4
  • Wikipedia:DFA_minimization
  • Minimization of DFAs
  • DFA Minimization