\documentclass{article}

\usepackage{xspace,graphicx,hyperref,paralist}

\newtheorem{illustration}{Illustration}[section]


\newcounter{exer}
\renewcommand{\theexer}{\thechapter:\arabic{exer}}

\newcommand{\FIXIT}[1]{\typeout #1 -- {\LARGE\sf #1}}

%---
\newcommand{\TM}{{Turing machine}\xspace}
\newcommand{\TMs}{{Turing machines}\xspace}
\newcommand{\NPCness}{{NP-completeness}\xspace}
\newcommand{\NPC}{{NP-complete}\xspace}
\newcommand{\NPH}{{NP-hard}\xspace}
\newcommand{\sfP}{{\sf P}\xspace}
\newcommand{\sfNP}{{\sf NP}\xspace}
\newcommand{\sfNPC}{{\sf NPC}\xspace}
\newcommand{\sfNPH}{{\sf NPH}\xspace}
\newcommand{\sfCoNP}{{\sf CoNP}\xspace}
\newcommand{\sfCoNPC}{{\sf CoNPC}\xspace}
\newcommand{\BA}{{B\"{u}chi automata}\xspace}
\newcommand{\BAon}{{B\"{u}chi automaton}\xspace}
\newcommand{\TL}{{Temporal Logic}\xspace}
\newcommand{\LTL}{{linear-time temporal logic}\xspace}
\newcommand{\CTL}{{Computational Tree Logic}\xspace}
\newcommand{\KS}{{Kripke structure}\xspace}
\newcommand{\KSs}{{Kripke structures}\xspace}
\newcommand{\OR}{{$\omega$-regular}\xspace}
%---


\oddsidemargin 0cm
\textwidth 17cm

\begin{document}


\title{\large\bf CS 3100 -- Models of Computation -- Fall 2011 --  Notes for L5}

\maketitle

\section{On DFA}

A {\em deterministic finite-state automaton} (DFA) models 
finite-state devices.
There are many real-life systems that can be modeled using DFA; 
some examples are:
\begin{compactitem}
\item C programs operating with finite memory,   
\item Scanners that check the syntax of tokens in a language
  ({\em e.g.}, strings, floating-point numbers, telephone numbers, etc.)
\item Almost all board-games
\item Binary decision diagrams (we will study them much later)
\end{compactitem}

\noindent We will mostly study DFAs at an abstract level.
%
We will then study how to express DFAs using regular expressions, and automatically
build them using tools such as {\tt ply}.

DFA are
specified through a transition graph
such as in Figure~\ref{fig:dfa-ex1}.
%--
It starts its operation in an initial state (in this case \verb|I|).
%--
When a DFA is situated in one of its reachable states $s$ and is fed
an input string $w$, it advances to a {\em unique} state as per its
transition graph.
%--
Formally, a {\em deterministic finite-state automaton}
$D$ is described by five quantities
presented as a tuple, $(Q,\Sigma,\delta,q_0,F)$, where:
\begin{itemize}
\item $Q$, a {\em finite nonempty} set of states;
\item $\Sigma$, a {\em finite nonempty} alphabet;
\item $\delta: Q\times \Sigma \rightarrow Q$, a {\em total}
	transition function;
	\index{$\delta$, for a DFA}
	\index{DFA Transition function}
	\index{Transition function!$\delta$}
	\index{Transition function!total}
\item $q_0\in Q$, an initial state; and
	\index{$q_0$}
\item $F\subseteq Q$, a {\em finite, possibly empty} set of
	final (or {\em accepting}) states.
	\index{State!final}
	\index{State!accepting}
	\index{Final state}
\end{itemize}
%--
%--
\begin{figure}
\centering\includegraphics[scale=0.5, angle = -90]{fig6_1.pdf}
\caption{A DFA that recognizes strings over $\{0,1\}$ ending with $1$}
\label{fig:dfa-ex1}
\end{figure}
%--

%-------------------------------------------------------
\begin{figure}[bt]
\begin{footnotesize}
\begin{verbatim}
/* Encoding of a DFA that accepts the language (0+1)*1 */
main() 
{ bool state=0; 
  char ch;
  while(1)
  { ch = getch();
    switch (state)
    { case I: switch-off the green light;
              switch (ch)
              { case 0 : break;
                case 1 : state=F;
              }
      case F: switch-on the green light;
              switch (ch)
              { case 0 : state=I;
                case 1 : break;
              }
    }
  }
}
\end{verbatim}
\end{footnotesize}
\caption{Pseudocode for the DFA of Figure~\ref{fig:dfa-ex1}}
\label{fig:dfa-ex1-program}
\end{figure}
%--
\begin{figure}
\centering\includegraphics[scale=0.5, angle = -90]{fig6_1_multi.pdf}
\caption{Multiple symbols labeling a transition in lieu of multiple
	transitions}
\label{fig:dfa-ex-multiple}
\end{figure}
%--


\begin{figure}
\centering\includegraphics[scale=0.5, angle = -90]{fig6_1_broken.pdf}
\caption{A DFA with unreachable (redundant) states}
\label{fig:dfa-ex-broken}
\end{figure}
%-------------------------------------------------------
For example, in Figure~\ref{fig:dfa-ex1}, $Q=\{I,F\}$,
$\Sigma=\{0,1\}$, $q_0=I$, $F=\{F\}$, and
$\delta$ is a total function that maps transitions as per this figure,
{\em i.e.},
\begin{verbatim}
{('I',0) : 'I', ('I',1) : 'F', ('F',0) : 'I', ('F',1) : 'F'}
\end{verbatim}

Sometimes, it is tedious to draw out $\delta$ as a total function because
most of the moves are to the ``black hole'' (BH) state: states into
which transitions can check in, but not check out\footnote{Also called 
RM or Roach Motel states.}
%
In that case, please add documentation that ``moves to the BH state
are not shown'' or something to that effect. 

One could have a DFA with multiple symbols labeling a single
	transition in lieu of separate transitions that bear
	these symbols, as shown in
	Figure~\ref{fig:dfa-ex-multiple}.
 One could have a DFA with truly unreachable states, as shown in
	Figure~\ref{fig:dfa-ex-broken}. These states (states X and Y
	in this example) may be removed without any loss of meaning.

%--
\begin{figure}
\centering\includegraphics[scale=0.5, angle = -90]{equal-changes.pdf}
\caption{Another example DFA}
\label{fig:dfa-ex2}
\end{figure}
%--

%
%--


The DFA in Figure~\ref{fig:dfa-ex1} is really encoding
programs similar to the one in
Figure~\ref{fig:dfa-ex1-program}.
%
All ``DFA programs'' are {\tt while(1)} loop controlled
{\tt switch} structures.
%
While in a certain state, a DFA decodes the current input symbol and decides to
either update its state or keep its current state (a DFA always moves; it may
decide to move back to its current state).
%
The next input symbol is decoded in this (possibly) updated state.
%
Whenever {\em any} final state (including the IF state)
is entered, the DFA turns on its {\em green light}.
%--
The green light stays on so long as the DFA stays in one of the final state, and
is turned off when it exits it.
%--
A DFA program is not allowed to use {\em any} other variable
than the single variable called {\tt state}.
%--
It cannot produce {\em any} other output than shine the green light.
%--
It appears to be programming at its simplest - yet, such humble
DFAs are enormously powerful and versatile!
%--

The $\delta$ function of a DFA is also commonly presented  as a table, with rows
being states, columns being inputs, with the final state(s)
starred.
%
For our example, we have
%--
\begin{footnotesize}
\begin{verbatim}
       input
       -----
state| 0   1
------------
 I   | I   F
*F   | I   F
\end{verbatim}
\end{footnotesize}
%--

A DFA is said to accept a string $s$ if its green-light is `on'
after processing that string; all other strings are
{\em rejected} by the DFA.
%--
However, note that a DFA ``never stops working''; after processing any string $s$,
it will be in a position to process any one of the input symbols $a$, and may
(depending on the DFA) accept or reject that string, $sa$.
%--
DFAs can be thought of as {\em string classifiers}, assigning a status
(accepted/rejected) for {\em every} string within $\Sigma^*$.
%
\index{String classifier}
\index{DFA!string classifier}
%--
The set of strings accepted by a DFA is said to be its {\em language}.
%--
	\index{Recognize}
	\index{Acceptance of strings}
A DFA is said to {\em recognize} its language (not {\em accept} its
language - the term `accept' is used for individual strings).
%
Formally speaking, a DFA is said to {\em accept} an input $x\in \Sigma^*$
if $x$ takes it from $q_0$ to one of its final states.
%
These ideas are captured by the following Python programs:

\begin{footnotesize}
\begin{verbatim}
# Some helper functions, and Dfa operations

def fst(p):
    """ First of a pair."""
    return p[0]

def snd(p):
    """ Second of a pair."""
    return p[1]

def fn_dom(F):
    """ For functions represented as hash-maps (dicts), return their domain as a set.
    """
    return {k for k in F.keys()}

def fn_range(F):
    """ For functions represented as hash-maps (dicts), return their range as a set.
    """    
    return {v for v in F.values()}

# More checks are possible perhaps... but here is most
def mk_dfa(Q, Sigma, Delta, q0, F):
    """Make a DFA with the given traits. Delta is supplied as a hash-map (dict).
    """
    assert(Sigma != {})
    #
    # Sigma is a set of strings of length 1. This check does it in one line
    assert(not(False in list(map(lambda x: len(x)==1, Sigma))))
    #
    # Delta must be a total function
    dom = fn_dom(Delta)
    states_dom = set(map(fst,dom))
    input_dom = set(map(snd,dom))
    state_targ = set(fn_range(Delta))
    #-- num state and input entries to match
    assert(states_dom == Q)
    assert(input_dom == Sigma)
    #
    #-- Mapping for every pair must be present
    assert(len(Delta)==len(Q)*len(Sigma))
    #
    # Targets must be in Q and non-empty
    assert((state_targ <= Q)&(state_targ != {}))
    # Initial state in Q
    assert(q0 in Q)
    # Final states subset of Q (could be empty, could be Q)
    assert(set(F) <= Q)
    # If all OK, return DFA as a dict
    return({"Q":Q, "Sigma":Sigma, "Delta":Delta, "q0":q0, "F":F})

# An example DFA being made

Q1 = {'S0','S1'}

Sigma1 = {'a','b'}

Delta1 = {('S0', 'a'): 'S0', ('S1', 'a'): 'S0', ('S1', 'b'): 'S1', ('S0', 'b'): 'S1'}

q01 = 'S0'

F1 = {'S1'}

DFA1 = mk_dfa(Q1,Sigma1,Delta1,q01,F1)

# Check that it's made properly

assert(DFA1 == {'Q': {'S1', 'S0'}, 'q0': 'S0', 'F': {'S1'}, 'Sigma': {'a', 'b'}, 'Delta': {('S0', 'a'): 'S0', ('S1', 'a'): 'S0', ('S1', 'b'): 'S1', ('S0', 'b'): 'S1'}})

def mktot(D):
    """ Given a partially specified DFA, make it total by transitioning to state BH wherever undefined.
    """
    add_delta = { (q,c) : "BH" for q in D["Q"] for c in D["Sigma"] if (q,c) not in D["Delta"] }
    #
    # print("<add_delta")
    # print(add_delta)
    # print("add_delta>")
    #
    bh_moves =  { ("BH", c): "BH" for c in D["Sigma"] }
    #
    add_delta.update(bh_moves)
    #
    # print(add_delta)
    #
    add_delta.update(D["Delta"])
    #
    return {"Q": D["Q"] | { "BH" }, "Sigma": D["Sigma"], "q0": D["q0"], "F": D["F"], "Delta": add_delta}

assert(mktot(DFA1) == {'Q': {'S1', 'S0', 'BH'}, 'q0': 'S0', 'Delta': {('S0', 'a'): 'S0', ('BH', 'a'): 'BH', ('S1', 'a'): 'S0', ('S1', 'b'): 'S1', ('S0', 'b'): 'S1', ('BH', 'b'): 'BH'}, 'Sigma': {'a', 'b'}, 'F': {'S1'}})
             
assert(mktot(mktot(DFA1)) == mktot(DFA1))


def prdfa(D):
        """Prints the DFA neatly.
        """
        Dt = mktot(D)
        # print(totdfa)
        print("")
        print("Q:", Dt["Q"])
        print("Sigma:", Dt["Sigma"])
        print("q0:", Dt["q0"])
        print("F:", Dt["F"])
        print("Delta:")
        print("\t".join(map(str,Dt["Q"])))
        print("----------------------------------------------------------------------------------------")
        for c in (Dt["Sigma"]):
            nxt_qs = [Dt["Delta"][(q, c)] for q in Dt["Q"]]
            print("\t".join(map(str, nxt_qs)) + "\t" + c)
            print("")


def prdfa_nomktot(D):
        """Prints the DFA neatly. Don't make it total, as we suspect a total one is given...
        """
        print("")
        print("Q:", D["Q"])
        print("Sigma:", D["Sigma"])
        print("q0:", D["q0"])
        print("F:", D["F"])
        print("Delta:")
        print("\t".join(map(str,D["Q"])))
        print("----------------------------------------------------------------------------------------")
        for c in (D["Sigma"]):
            nxt_qs = [D["Delta"][(q, c)] for q in D["Q"]]
            print("\t".join(map(str, nxt_qs)) + "\t" + c)
            print("")            

# Some ideas for printing obtained from Andrew Badr's pretty printer in his DFA package
# I've made it so that we can pretty-print NFA also (so undefined delta moves are OK)
#
def pr_nobh(D):
        """Prints the DFA nicely - don't list transitions to/from black-holes, i.e. BH
        """
        Dt = mktot(D)
        # print(totdfa)
        print("")
        print("Q:", Dt["Q"])
        print("Sigma:", Dt["Sigma"])
        print("q0:", Dt["q0"])
        print("F:", Dt["F"])
        print("Delta:")
        print("\t".join(map(str,Dt["Q"])))
        print("----------------------------------------------------------------------------------------")
        for c in (Dt["Sigma"]):
            nxt_qs = [Dt["Delta"][(q, c)] for q in Dt["Q"] ]
            print("\t".join(map(str, nxt_qs)) + "\t" + c)
            print("")
            

def step_dfa(D, q, c):
    """Run DFA D from state q on character c. Return the next state.
    """
    assert(c in D["Sigma"])
    assert(q in D["Q"])
    return D["Delta"][(q,c)]

def run_dfa(D, q, s):
    """Run DFA D from state q on string S. Return the next state. We run DFAs to run on "" also (empty).
    """
    # Don't run DFAs on empty strings
    return q if s=="" else run_dfa(D, step_dfa(D, q, s[0]), s[1:])

def accepts(D, q, s):
    """ Checks for DFA acceptance.
    """
    return run_dfa(D, q, s) in D["F"]
\end{verbatim}
\end{footnotesize}

\noindent{\bf Drill Problem:\/}
Define the Python function \verb|recognizes(D, n)| that returns
all strings of length $\leq$ \verb|n| recognized by the DFA {\tt D}.
{\em Hint:\/} Can you use {\tt nthnumeric} to test candidate strings? How?

\noindent{\bf Drill Problem:\/}
What is wrong with trying to define 
a different function \verb|recognizes(D)| that returns
all strings of all lengths recognized by the DFA {\tt D}?
%
What is a test you can subject \verb|D| to such that 
you can define such a function for all the
\verb|D| that passes the test? 


\begin{quote}
\noindent{\bf REGULAR LANGUAGE:\/}
 A language $L$ is defined to be {\em regular} if there is a DFA $D$
	such that $L={\cal L}(D)$.
	\index{Regular}
	\index{Language}
	\index{Language!regular}
\end{quote}

If $L$ is the language of a DFA $D$, then when
the DFA is run on any string $s\in L$,
it leaves the DFA in one of its accepting states.

Any string {\bf not} in the language of the DFA $D$ is
a language in the complement of the language $L$.
Thus, this string is still over the same alphabet
 but leaves the DFA in a non-final state.



\section{Examples of DFA}

\noindent Unless you design many DFAs ``by hand,'' you will not
learn to appreciate  how to design them. That is precisely what
we are about to embark on.

\begin{enumerate}
\item  Define, using set comprehension,
  the regular language recognized by the DFA of
  Figure~\ref{fig:dfa-ex2}.

\item For all languages defined in {\tt notes3.pdf} that are regular
  languages, design a DFA.

\item Define a DFA that accepts all strings over \{0,1\} fed LSB-first
  such that these strings when interpreted according to standard 
  binary conventions defines numbers which are evenly divisible by 3.

\item Define a DFA that accepts all strings over \{0,1\} 
  such that every block of five consecutive positions contains at 
  least two 0s.

\item Define a DFA for the language defined by the concatenation of
  the languages denoted by DFA of Figures~\ref{fig:dfa-ex1} and
  \ref{fig:dfa-ex2}.

\end{enumerate}


\end{document}

