Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
lfa:2024:lab02 [2024/10/11 19:31]
stefan.sterea
lfa:2024:lab02 [2024/10/12 01:40] (current)
stefan.sterea
Line 279: Line 279:
 The program will be interpreted even if ''​Void''​ does not correctly implement the methods in ''​Tree''​ (though there are ways to enforce it at runtime. See [[https://​blog.teclado.com/​python-abc-abstract-base-classes/​|here]]). The program will be interpreted even if ''​Void''​ does not correctly implement the methods in ''​Tree''​ (though there are ways to enforce it at runtime. See [[https://​blog.teclado.com/​python-abc-abstract-base-classes/​|here]]).
  
-The class constructor is the ''​__init__(self):''​ method. Also note the mandatory presence of ''​self'',​ which is the Python equivalent of ''​this''​. Each method will receive the object it is called on as the first argument.+The class constructor is the ''​%%__init__(self):​%%''​ method. Also note the mandatory presence of ''​self'',​ which is the Python equivalent of ''​this''​. Each method will receive the object it is called on as the first argument.
  
-The method ''​def __str__(self):''​ is the Python equivalent for ''​toString()''​. An object can be displayed using the function ''​str''​.+The method ''​%%def __str__(self):​%%''​ is the Python equivalent for ''​toString()''​. An object can be displayed using the function ''​str''​.
  
 ===== The functional style ===== ===== The functional style =====
Line 366: Line 366:
 d1: dict[str, int]  # dictionary with string keys and integer values d1: dict[str, int]  # dictionary with string keys and integer values
 </​code>​ </​code>​
-  ​* for functions/​methods:​ ''​def <​func_name>​([<​param>:​ <​type>,​ ...]) -> <​return_type>''​:+ 
 +  ​* for functions/​methods:​ ''​def <​func_name>​([<​param>:​ <​type>,​ ...]) -> <​return_type>''​ 
 +  * you can also type a variable with ''​%%Callable[[<​param_type1>,​ ...], <​return_type>​]%%''​ to hold functions or lambdas 
 <code python> <code python>
 def hello() -> str: def hello() -> str:
Line 376: Line 379:
         ...         ...
 </​code>​ </​code>​
-  ​* for generic classes: extend either a generic class (such as list[_], set[_] or tuple[_]) or extend the Generic class (introduced by the typing module):+ 
 +* for generic classes: extend either a generic class (such as list[_], set[_] or tuple[_]) or extend the Generic class (introduced by the typing module): 
 <code python> <code python>
 from typing import TypeVar, Generic from typing import TypeVar, Generic
  
 StateType = TypeVar("​StateType"​) # !!! important: type variables must be declared and initialised before they are used StateType = TypeVar("​StateType"​) # !!! important: type variables must be declared and initialised before they are used
-class DFA(Generic[StateType]):​+class DFA(Generic[StateType]): ​  # you can also write 'class DFA[StateType]:'​ instead
     def next_state(self,​ from_state: StateType, token: str) -> StateType:     def next_state(self,​ from_state: StateType, token: str) -> StateType:
         ...         ...
Line 404: Line 409:
  
 Useful type hints: Useful type hints:
-  * ''​int,​ str, bool, float etc.''​ : the basic datatypes (charaters ​are hinted as strings, as python does not make the distinction) +  * ''​int,​ str, bool, float etc.''​ : the basic datatypes (characters ​are hinted as strings, as python does not make the distinction) 
-  * ''​list[type], set[type], frozenset[type],​ dict[key_type,​ val_type]''​: basic data collections ​(items introduced in ''​set''​s and ''​frozenset''​s and the keys of dictionaries need to be hashable: see the [[lfa:​dictionaries|appendix for python hashing]]) +  * list[type], set[type], frozenset[type],​ dict[key_type,​ val_type]: basic data collections 
-  * ''​Any'':​ a type is compatible with any other type (if no type hint is specified, this is what type checkers usually default to) +  ​* ''​Any'':​ a type is compatible with any other type (if no type hint is specified, this is what type checkers usually default to) 
-  * ''​Callable[ [<​param_types>​...],​ <​return_type>​]'':​ this defines a function with a given signature+  * ''​%%Callable[[<​param_types>​...],​ <​return_type>​]%%'':​ this defines a function with a given signature
   * ''<​type1>​ | <​type2>'':​ the ''​|''​ operator allows us to indicate that a given object can be one of two(or more) types   * ''<​type1>​ | <​type2>'':​ the ''​|''​ operator allows us to indicate that a given object can be one of two(or more) types
   * ''​None'':​ represents the lack of a value (or an explicit None value); useful to mark functions which have no return value, or that a value may be purposefully missing (in combination with the ''​|''​ operator), and a None check may be necessary   * ''​None'':​ represents the lack of a value (or an explicit None value); useful to mark functions which have no return value, or that a value may be purposefully missing (in combination with the ''​|''​ operator), and a None check may be necessary
-full documentation ​of the python typing module: ​[[https://​docs.python.org/​3/​library/​typing.html]]+  * The official typing ​documentation [[https://​docs.python.org/​3/​library/​typing.html|here]]
  
-===== Exercises ​=====+===== Practice ​=====
  
-**1.1.** Write function ''​max_elem(lstart, stop)'' that determines the maximum element between the start and stop positions.+The task of this lab will be to implement the accepting procedure of DFA in Pythonin order to get familiar with Python's language constructs and get a start into working with DFAs in code.
  
-**1.2.** Write function ''​longest_positive_sequence(l)''​ that determines the longest sequence ​of positive integers from list. For example for the list ''​[1,​3,​-1,​2,​0,​1,​5,​4,​-2,​4,​5,​-3,​0,​1,​2]''​ it returns ''​[2,​0,​1,​5,​4]''​.+Reading ​textual representation ​of a DFA and a word, output whether or not the DFA accepts the word. 
 +The DFA will be represented as:
  
-**1.3.** Write a function ''​is_palindrome(l)''​ that checks if a list is a palindrome (it returns True/​False).+**#states**
  
-**1.4.** Write a function ''​chr_list(s)''​ that determines ​the list of characters which occur in string. For example for the string ''"​limbaje formale"''​ it returns ''"​limbaje for"''​.+//the labels ​of the states, each on separate line//
  
-**1.5.** Write function ''​get_frequency(s)'' ​that returns ​dictionary with the frequency of every character that appears ​in the string.+**#initial** 
 + 
 +//the label of the initial state// 
 + 
 +**#​accepting** 
 + 
 +//the labels of the final states, each on separate line// 
 + 
 +**#​alphabet** 
 + 
 +//the symbols of the alphabet of the DFA, each on a separate line// 
 + 
 +**#​transitions** 
 + 
 +//source state// **:** //read character// **>** //​destination state// ​  //(each transition on a separate line)// 
 + 
 +Example: 
 + 
 +<​code>​ 
 +#states 
 +s0 
 +s1 
 +s2 
 +#initial 
 +s0 
 +#​accepting 
 +s1 
 +#alphabet 
 +
 +
 +
 +#​transitions 
 +s0:​b>​s2 
 +s0:​c>​s0 
 +s1:​a>​s2 
 +s1:​c>​s1 
 +s2:​a>​s1 
 +s2:​b>​s1 
 +s2:​c>​s2 
 +</​code>​ 
 + 
 +represents the following DFA: 
 +{{:​lfa:​2024:​lab2-dfa-example.png?​200|}} 
 + 
 +You should write a DFA class to keep the internal state and input left unconsumed and implement an ''​accept''​ method. 
 + 
 +You may choose how to take input: you can read the DFA from file, you can receive ​the path to the file as an argument to the Python program, you can take the word as another argument or in the same file as the DFA. 
 + 
 +Example of reading command line arguments and working with files: 
 +<code python>​ 
 +import sys 
 + 
 +def read_lines(file_path:​ str) -> list[str]:​ 
 +    try: 
 +        # '​with'​ creates a context manager which handles file closing 
 +        with open(file_path,​ '​r'​) as file: 
 +            return file.readlines() 
 +    except FileNotFoundError:​ 
 +        print(f"​Error:​ File '​{file_path}'​ not found."​) 
 + 
 +def main(): 
 +    if len(sys.argv) != 2: 
 +        print(f"​Usage:​ python3 <​file_path>"​) 
 +        sys.exit(1) 
 + 
 +    file_path = sys.argv[1] 
 +    lines = read_file(file_path) 
 +    print(lines) 
 + 
 +if __name__ == "​__main__":​ 
 +    main() 
 +</​code>​
  
-**1.6.** Starting from the example in the **Classes and inheritance** section, implemented the ''​Node''​ class (that inherits from ''​Tree''​) and it's methods.