Skip to the content.

:warning: 非決定性有限オートマトン(NFA)
(automaton/nfa.hpp)

概要

NFA $N=(Q,\Sigma,\Delta,s,F)$ は以下を満たすもの.

以下のようにして $\Delta:2^Q\times\Sigma\to 2^Q$ とみなす.

$\hat{\Delta}:2^Q\times\Sigma^*\to 2^Q$ を以下のように定義する.

$x\in\Sigma^*$ について,$\hat{\Delta}(s,x)\cap F\neq\emptyset$ ならば $x$ は $N$ によって 受理される,そうでないならば 拒否される という.

言語 $L$ について,任意の文字列 $x$ に対し $x\in L$ と $N$ が $x$ を受理することが同値であるとき,$L$ は $N$ によって受理されるという.

DFA との関係

DFA は自然に NFA とみなせる.

逆に NFA は DFA で再現できる.状態集合を $2^Q$ と思えばよい.

従って DFA と NFA の表現力は等価である.

扱いやすさの面では DFA が,少ない状態数で表すには NFA が便利であるから使い分けが重要.

Depends on

Code

#pragma once

#include "./dfa.hpp"

template <int c_min = 'a', int c_max = 'z'>
class NFA {
  using t_dfa = DFA<c_min, c_max>;
  using t_nfa = NFA<c_min, c_max>;
  static const int c_size = c_max - c_min + 1;

 public:
  NFA() {}
  NFA(int size_, int start_)
      : _size(size_),
        _start(start_),
        _final(size_, false),
        map(size_, vector(c_size, vector<bool>(size_, false))) {}
  void add(int p, char c, int q) { map[p][c - c_min][q] = true; }
  void remove(int p, char c, int q) { map[p][c - c_min][q] = false; }
  void set_final(int p, bool f) { _final[p] = f; }
  bool get_final(int p) { return _final[p]; }

  t_dfa subset_construction() {
    using T = long long;
    map<T, int> index;
    vector<vector<int>> map1;
    int size1 = 0;
    T start1 = T(1) << _start;
    stack<T> st;
    index[start1] = size1++;
    st.push(start1);
    while (!st.empty()) {
      T x = st.top();
      st.pop();
      vector<int> map_cur(c_size, -1);
      for (int c = 0; c < c_size; c++) {
        T y = 0;
        for (int i = 0; i < _size; i++)
          if ((x >> i) & 1)
            for (int j = 0; j < _size; j++) y |= T(map[i][c][j]) << j;
        if (!index.contains(y)) {
          index[y] = size1++;
          st.push(y);
        }
        map_cur[c] = index[y];
      }
      map1.push_back(map_cur);
    }
    vector<bool> final1(size1, false);
    for (auto [x, i] : index) {
      for (int j = 0; j < _size; j++)
        if (((x >> j) & 1) && _final[j]) final1[i] = 1;
    }
    return t_dfa(index.size(), start1, final1, map1);
  }

 private:
  int _size, _start;
  vector<bool> _final;
  vector<vector<vector<bool>>> map;
};

/**
 * @brief 非決定性有限オートマトン(NFA)
 * @docs docs/automaton/nfa.md
 */
#line 2 "automaton/nfa.hpp"

#line 2 "automaton/dfa.hpp"

template <int c_min = 'a', int c_max = 'z'>
class DFA {
  using t_dfa = DFA<c_min, c_max>;
  static const int c_size = c_max - c_min + 1;

 public:
  DFA() {}
  DFA(int size, int start)
      : _size(size),
        _start(start),
        _final(size, false),
        map(size, vector<int>(c_size, -1)) {}
  DFA(int size, int start, const vector<vector<int>> &map_)
      : _size(size), _start(start), _final(size, false), map(map_) {}
  DFA(int size, int start, const vector<bool> final_,
      const vector<vector<int>> &map_)
      : _size(size), _start(start), _final(final_), map(map_) {}
  void set(int p, char c, int q) { map[p][c - c_min] = q; }
  int get(int p, char c) { return map[p][c - c_min]; }
  void set_final(int p, bool f) { _final[p] = f; }
  bool get_final(int p) { return _final[p]; }

  t_dfa normalize() {
    vector<bool> seen(_size, false);
    vector<int> index(_size, -1);
    vector<int> states;
    queue<int> qu;
    qu.push(_start);
    while (!qu.empty()) {
      int x = qu.front();
      qu.pop();
      seen[x] = true;
      index[x] = states.size();
      states.push_back(x);
      for (int j = 0; j < c_size; j++) {
        int y = map[x][j];
        if (seen[y]) continue;
        seen[y] = true;
        qu.push(y);
      }
    }

    int size1 = states.size();
    vector<bool> final1(size1, false);
    for (int i = 0; i < size1; i++) final1[i] = _final[states[i]];
    vector<vector<int>> map1(size1, vector<int>(c_size, -1));
    for (int i = 0; i < size1; i++)
      for (int j = 0; j < c_size; j++) map1[i][j] = index[map[states[i]][j]];
    return t_dfa(size1, index[_start], final1, map1);
  }

  t_dfa minimize() {
    vector<int> partition(_size, -1);
    {
      int accept = -1, reject = -1;
      for (int i = 0; i < _size; i++)
        if (_final[i])
          partition[i] = accept == -1 ? (accept = i) : accept;
        else
          partition[i] = reject == -1 ? (reject = i) : reject;
    }

    vector<int> partition_new(_size, -1);
    while (true) {
      fill(partition_new.begin(), partition_new.end(), -1);
      for (int i = 0; i < _size; i++) {
        if (partition_new[i] != -1) continue;
        partition_new[i] = i;
        for (int j = i + 1; j < _size; j++)
          if (partition[i] == partition[j] && equivalent(i, j, partition))
            partition_new[j] = i;
      }
      if (partition == partition_new) break;
      swap(partition, partition_new);
    }

    int size1 = 0;
    vector<int> index(_size, -1), leader;
    vector<bool> final1;
    for (int i = 0; i < _size; i++)
      if (partition[i] == i) {
        index[i] = size1++;
        leader.push_back(i);
        final1.push_back(_final[i]);
      } else {
        index[i] = index[partition[i]];
      }
    vector<vector<int>> map1(size1, vector<int>(c_size, -1));
    for (int i = 0; i < size1; i++)
      for (int j = 0; j < c_size; j++) map1[i][j] = index[map[leader[i]][j]];
    return t_dfa(size1, index[_start], final1, map1).normalize();
  }

  bool operator==(const t_dfa &d) const {
    if (_size != d._size) return false;
    if (_start != d._start) return false;
    if (_final != d._final) return false;
    return map == d.map;
  }
  int size() { return _size; }
  int start() { return _start; }

 private:
  int _size, _start;
  vector<bool> _final;
  vector<vector<int>> map;

  bool equivalent(int i, int j, const vector<int> &partition) {
    if (i == j) return true;
    for (int k = 0; k < c_size; k++)
      if (partition[map[i][k]] != partition[map[j][k]]) return false;
    return true;
  }
};

/**
 * @brief 決定性有限オートマトン(DFA)
 * @docs docs/automaton/dfa.md
 */
#line 4 "automaton/nfa.hpp"

template <int c_min = 'a', int c_max = 'z'>
class NFA {
  using t_dfa = DFA<c_min, c_max>;
  using t_nfa = NFA<c_min, c_max>;
  static const int c_size = c_max - c_min + 1;

 public:
  NFA() {}
  NFA(int size_, int start_)
      : _size(size_),
        _start(start_),
        _final(size_, false),
        map(size_, vector(c_size, vector<bool>(size_, false))) {}
  void add(int p, char c, int q) { map[p][c - c_min][q] = true; }
  void remove(int p, char c, int q) { map[p][c - c_min][q] = false; }
  void set_final(int p, bool f) { _final[p] = f; }
  bool get_final(int p) { return _final[p]; }

  t_dfa subset_construction() {
    using T = long long;
    map<T, int> index;
    vector<vector<int>> map1;
    int size1 = 0;
    T start1 = T(1) << _start;
    stack<T> st;
    index[start1] = size1++;
    st.push(start1);
    while (!st.empty()) {
      T x = st.top();
      st.pop();
      vector<int> map_cur(c_size, -1);
      for (int c = 0; c < c_size; c++) {
        T y = 0;
        for (int i = 0; i < _size; i++)
          if ((x >> i) & 1)
            for (int j = 0; j < _size; j++) y |= T(map[i][c][j]) << j;
        if (!index.contains(y)) {
          index[y] = size1++;
          st.push(y);
        }
        map_cur[c] = index[y];
      }
      map1.push_back(map_cur);
    }
    vector<bool> final1(size1, false);
    for (auto [x, i] : index) {
      for (int j = 0; j < _size; j++)
        if (((x >> j) & 1) && _final[j]) final1[i] = 1;
    }
    return t_dfa(index.size(), start1, final1, map1);
  }

 private:
  int _size, _start;
  vector<bool> _final;
  vector<vector<vector<bool>>> map;
};

/**
 * @brief 非決定性有限オートマトン(NFA)
 * @docs docs/automaton/nfa.md
 */
Back to top page