====== 2. Deterministic finite automata ====== ===== Classes in Python ===== Python supports a limited version of Object-Oriented programming, which includes **class definitions** and **inheritance**. The concept of **interface** and **interface implementation** is absent. Hence, when inheriting a function, it is the job of the programmer to make sure a method is overloaded correctly (otherwise it is just another definition of the class). Below, we illustrate some examples of Python's object-oriented idiom: class Example: # the class constructor. def __init__(self,param1,param2): # the keyword self is similar to this from Java # it is the only legal mode of initialising and referring class member variables self.member1 = param1 # here member2 is a local variable, which is not visible outside of the constructor member2 = param2 def fun(self): # a member function must always refer self as shown here. Otherwise it is just a function # defined in the scope of the class, not a member function. return 0 def plus(self,x,y): return x + y # this is the equivalent of Java's toString method def __str__(self): string = ... return string #global scope #class instantiation e = Example(1,2) #method calls: e.fun() print(e) ===== 2.1. The class Dfa (Python) ===== **2.1.1.** Define the class ''Dfa'' which encodes deterministic finite automata. It must store: * the alphabet * the delta function * the initial state * the set of final states **Optional:** you may consider defining a class ''State'' to encode more general Dfas where states are not confined to integers. This will be useful later in your project. However, you will need to define a hash-function in order to use dictionaries over states. More details, google ''hashing in Python''. **2.1.2.** Define a constructor for Dfas, which takes a multi-line string of the following form: ... ... ... where: * the initial state is given on the first line of the input * each of the subsequent lines encode transitions (states are integers) * the last line encodes the set of final states. Example: 0 0 a 1 1 b 2 2 a 0 1 2 **2.1.3.** Implement a member function which takes a **configuration** (pair of state and rest of word) and returns the next configuration. **2.1.4.** Implement a member function which verifies if a word is **accepted** by a Dfa. ===== 2.2. The Dfa Algebraic Datatype (Haskell) ===== During the lecture, Dfa states were encoded as integers. As we will soon see, we will need to provision our implementation, so that other types may encode states. * Should the ADT ''DFA'' be **monomorphic** or **polymorphic**? Also, we shall require a few constraints on what a proper state type should be. States should be: (i) **comparable** via equality, (ii) support an **ordering**. Later on we may add: * new constraints * **operations** which are specific to states only. How can we **group** all these constraints and support for future state operations? Finally, in order to encode transitions and sets, we need the ''Map'' and ''Set'' datatypes which are available in their own modules: {- We do import the data constructor Map and the infix function (!) as unqualified, to make them easier to use (Map.Map and Map.(!) is not very legible) -} import Data.Map (Map, (!)) {- the keyword qualified forces us to prefix each function call from the module Data.Map with "Map." this is useful for two reasons: - some function names overlap - it makes the code more legible, by making the programmer aware of the module location of the called function -} import qualified Data.Map as Map import Data.Set (Set) import qualified Data.Set as Set
** How to choose between lists and sets during the implementation?** * Do you need to make sure elements are unique? (go for sets) * Do you need to iterate a lot over elements, and the collection size is not really big (go for lists)
**2.2.1.** Implement the datatype ''DFA''. It must store: * the alphabet * the delta function * the initial state * the set of final states ---- **2.2.2.** Define a function which takes a string of the following form showed below, and returns a DFA **with states as integers**: ... ... ... where: * the initial state is given on the first line of the input * each of the subsequent lines encode transitions (states are integers) * the last line encodes the set of final states. Example: 0 0 a 1 1 b 2 2 a 0 1 2 **Hint:** Use ''splitBy'' from PP. ---- **2.2.3.** Enroll the DFA type in class Show. **2.2.4.** Implement function which takes a DFA and a **configuration** (pair of state and rest of word) and returns the next configuration. **2.2.5.** Implement a function which verifies if a word is **accepted** by a Dfa. What kind of general list-operation best matches the accepting process? ===== 2.3. Dfa practice ===== Write Dfas and test them using your implementation, for the following languages: * **2.3.1.** $ L=\{w \in \{0,1\}^* \text{ | w contains an odd number of 1s} \} $ * **2.3.2.** The language of binary words which contain **exactly** two ones * **2.3.3.** The language of binary words which encode odd numbers (the last digit is least significative) * **2.3.4.** (hard) The language of words which encode numbers divisible by 3.