Coverage for /home/marcofavorito/workfolder/pythomata/pythomata/core.py : 82%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2"""The core module."""
4from abc import ABC, abstractmethod
5from typing import List, TypeVar, Generic, Set, Optional
7StateType = TypeVar('StateType')
8SymbolType = TypeVar('SymbolType')
11class Alphabet(Generic[SymbolType], ABC):
12 """Abstract class to represent a finite alphabet."""
14 @abstractmethod
15 def get_symbol(self, index: int) -> SymbolType:
16 """
17 Get the symbol of the alphabet, given the index.
19 :param index: the index.
20 :return: the corresponding symbol.
21 :raises ValueError: if there is not any symbol for that index.
22 """
24 @abstractmethod
25 def get_symbol_index(self, symbol: SymbolType) -> int:
26 """
27 Get the index of a symbol of the alphabet.
29 :param symbol: the symbol.
30 :return: its index.
31 :raises ValueError: if the symbol does not belong to the alphabet.
32 """
34 @property
35 @abstractmethod
36 def size(self) -> int:
37 """
38 Get the size of the alphabet.
40 :return: the size of the alphabet.
41 """
43 def contains(self, symbol: SymbolType) -> bool:
44 """
45 Check if a symbol is part of the alphabet.
47 :param symbol: the symbol.
48 :return: True if the symbol if part of the alphabet, False otherwise.
49 """
50 try:
51 index = self.get_symbol_index(symbol)
52 if index < 0 or index >= self.size:
53 return False
54 return symbol == self.get_symbol(index)
55 except ValueError:
56 return False
58 @abstractmethod
59 def __iter__(self):
60 """Iterate over the number of symbols."""
62 def __len__(self):
63 """Return the size of the alphabet."""
64 return self.size
66 def __eq__(self, other) -> bool:
67 """Check that two alphabet are equal."""
68 return isinstance(other, Alphabet) and set(self) == set(other)
71class FiniteAutomaton(Generic[StateType, SymbolType], ABC):
72 """This is an interface for any finite state automaton (DFAs, NFAs...)."""
74 @property
75 @abstractmethod
76 def states(self) -> Set[StateType]:
77 """
78 Get the set of states.
80 :return: the set of states of the automaton.
81 """
83 @property
84 @abstractmethod
85 def initial_states(self) -> Set[StateType]:
86 """Get the set of initial states."""
88 @property
89 @abstractmethod
90 def final_states(self) -> Set[StateType]:
91 """Get the set of final states."""
93 @abstractmethod
94 def get_successors(self, state: StateType, symbol: SymbolType) -> Set[StateType]:
95 """
96 Get the successors of the state in input when reading a symbol.
98 :param state: the state from which to compute the successors.
99 :param symbol: the symbol of the transition.
100 :return: the set of successor states.
101 :raises ValueError: if the state does not belong to the automaton, or the symbol is not correct.
102 """
104 @property
105 def size(self) -> int:
106 """
107 Get the size of the automaton.
109 :return: the number of states of the automaton.
110 """
111 return len(self.states)
113 def is_accepting(self, state: StateType) -> bool:
114 """
115 Check whether a state is accepting.
117 :param state: the state of the automaton.
118 :return: True if the state is accepting, false otherwise.
119 :raises ValueError: if the state does not belong to the automaton.
120 """
121 return state in self.final_states
123 def accepts(self, word: List[SymbolType]) -> bool:
124 """
125 Check whether the automaton accepts the word.
127 :param word: the list of symbols.
128 :return: True if the automaton accepts the word, False otherwise.
129 """
130 current_states = self.initial_states
131 for symbol in word:
132 next_current_states = set()
133 for state in current_states:
134 next_current_states.update(self.get_successors(state, symbol))
135 current_states = next_current_states
137 return any(self.is_accepting(state) for state in current_states)
140class DFA(Generic[StateType, SymbolType], FiniteAutomaton[StateType, SymbolType], ABC):
141 """An interface for a deterministic finite state automaton."""
143 @property
144 @abstractmethod
145 def initial_state(self) -> StateType:
146 """Get the (unique) initial state."""
148 @abstractmethod
149 def get_successor(self, state: StateType, symbol: SymbolType) -> Optional[StateType]:
150 """
151 Get the (unique) successor.
153 If not defined, return None.
154 """
156 @property
157 def initial_states(self) -> Set[StateType]:
158 """Get the set of initial states."""
159 return {self.initial_state}
161 def get_successors(self, state: StateType, symbol: SymbolType) -> Set[StateType]:
162 """Get the successors."""
163 successor = self.get_successor(state, symbol)
164 return {successor} if successor is not None else set()
167# not used yet
168class AutomataOperations(Generic[StateType, SymbolType], ABC):
169 """An interface for automata operations."""
171 @abstractmethod
172 def determinize(self) -> DFA[StateType, SymbolType]:
173 """Make the automaton deterministic."""
175 @abstractmethod
176 def minimize(self) -> FiniteAutomaton[StateType, SymbolType]:
177 """Minimize the automaton."""