mirror of
https://codeberg.org/JasterV/uni-lab.git
synced 2026-04-26 18:40:03 +00:00
add python labs
This commit is contained in:
parent
6791f4ff5b
commit
15f54af40a
6 changed files with 501 additions and 0 deletions
122
python-lab/Finite-Automatons-Computation/.gitignore
vendored
Normal file
122
python-lab/Finite-Automatons-Computation/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/python
|
||||||
|
# Edit at https://www.gitignore.io/?templates=python
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/python
|
||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api
|
||||||
22
python-lab/Finite-Automatons-Computation/README.md
Normal file
22
python-lab/Finite-Automatons-Computation/README.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# FINITE AUTOMATONS COMPUTATION
|
||||||
|
|
||||||
|
A program that runs finite automatons and operate with them (reading, determinizing and minimizing).
|
||||||
|
I'm working on automaton algebra operations such as concatenation, union and intersection. ^^
|
||||||
|
|
||||||
|
To work with the program you need to create a json file with the automaton settings.
|
||||||
|
|
||||||
|
The json must contains the following attributes:
|
||||||
|
|
||||||
|
+ states -> A map whose keys are the label of the state
|
||||||
|
and whose values are a list with each type
|
||||||
|
corresponding to the state.
|
||||||
|
The types are: 'I' for initial states,
|
||||||
|
'F' for final states,
|
||||||
|
'N' for non-initial and non-final states.
|
||||||
|
+ alphabet -> A list with each symbol accepted by the automaton.
|
||||||
|
+ transitions -> A map whose keys are the label of the state
|
||||||
|
and whose values are another map that represents
|
||||||
|
each transition for each symbol for the corresponding state.
|
||||||
|
|
||||||
|
The transition map must have as key a valid symbol on the alphabet
|
||||||
|
and as value a list of the states the corresponding state goes with that symbol.
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"states": {
|
||||||
|
"0": ["I", "F"],
|
||||||
|
"1": ["N"],
|
||||||
|
"2": ["F"]
|
||||||
|
},
|
||||||
|
"alphabet": [
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
],
|
||||||
|
"transitions": {
|
||||||
|
"0": {
|
||||||
|
"b" : ["0"],
|
||||||
|
"a" : ["1"]
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"a" : ["2"],
|
||||||
|
"b" : ["1"]
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"a" : ["2"],
|
||||||
|
"b" : ["2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"states": {
|
||||||
|
"0": ["I"],
|
||||||
|
"1": ["I"],
|
||||||
|
"2": ["F"]
|
||||||
|
},
|
||||||
|
"alphabet": [
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
],
|
||||||
|
"transitions": {
|
||||||
|
"0": {
|
||||||
|
"b" : [],
|
||||||
|
"a" : ["1"]
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"a" : ["2"],
|
||||||
|
"b" : []
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"a" : ["2"],
|
||||||
|
"b" : ["2", "0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
247
python-lab/Finite-Automatons-Computation/src/automaton.py
Normal file
247
python-lab/Finite-Automatons-Computation/src/automaton.py
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from queue import Queue
|
||||||
|
import random
|
||||||
|
|
||||||
|
empty_set = u"\u00F8"
|
||||||
|
lmbda = u"\u03BB"
|
||||||
|
|
||||||
|
|
||||||
|
class FSM():
|
||||||
|
def __init__(self, json: dict):
|
||||||
|
try:
|
||||||
|
states = json["states"]
|
||||||
|
alphabet = json["alphabet"]
|
||||||
|
transitions = json["transitions"]
|
||||||
|
except Exception:
|
||||||
|
raise ValueError(
|
||||||
|
"The json file must have the keys 'states', 'alphabet' and 'transitions'")
|
||||||
|
self.__assert_states(states)
|
||||||
|
self.__assert_alphabet(alphabet)
|
||||||
|
self.__assert_transitions(transitions, alphabet, states)
|
||||||
|
# Create all the Automaton Attributes
|
||||||
|
self.__states = set(states.keys())
|
||||||
|
self.__initial_states = set(
|
||||||
|
filter(lambda state: 'I' in states[state], states))
|
||||||
|
self.__final_states = set(
|
||||||
|
filter(lambda state: 'F' in states[state], states))
|
||||||
|
self.__alphabet = set(alphabet)
|
||||||
|
self.__transitions = transitions
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# ----------------- PUBLIC METHODS --------------------
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
def determinize(self):
|
||||||
|
""" This method determinize the automata
|
||||||
|
using BFS algorithm with a Queue
|
||||||
|
"""
|
||||||
|
queue = Queue()
|
||||||
|
transitions = dict()
|
||||||
|
initial_state = tuple(self.__initial_states)
|
||||||
|
queue.put(initial_state)
|
||||||
|
print("Determinizing automaton... ")
|
||||||
|
while not queue.empty():
|
||||||
|
curr_state = queue.get()
|
||||||
|
if curr_state not in transitions:
|
||||||
|
transitions[curr_state] = dict()
|
||||||
|
for symbol in self.__alphabet:
|
||||||
|
next_state = self.__get_next_state(curr_state, symbol)
|
||||||
|
if next_state == empty_set:
|
||||||
|
if empty_set not in transitions:
|
||||||
|
self.__add_empty_set(transitions)
|
||||||
|
transitions[curr_state][symbol] = [next_state]
|
||||||
|
queue.put(next_state)
|
||||||
|
self.__states = set(transitions.keys())
|
||||||
|
self.__initial_states = set([initial_state])
|
||||||
|
self.__final_states = set(
|
||||||
|
filter(lambda state: self.__is_final_state(state), transitions.keys()))
|
||||||
|
self.__transitions = transitions
|
||||||
|
print("Automaton determinized! Enter 'show' to see the changes\n")
|
||||||
|
|
||||||
|
def read(self, word):
|
||||||
|
""" Represents word reading
|
||||||
|
"""
|
||||||
|
if not self.is_deterministic():
|
||||||
|
print("\nThis automaton is non-deterministic")
|
||||||
|
self.determinize()
|
||||||
|
init_state = list(self.__initial_states)[0]
|
||||||
|
print("Reading word...")
|
||||||
|
self.__read(word, init_state)
|
||||||
|
|
||||||
|
def minimize(self):
|
||||||
|
if not self.is_deterministic():
|
||||||
|
print("\nThis automaton is non-deterministic")
|
||||||
|
self.determinize()
|
||||||
|
eq_classes = [self.__states - self.__final_states, self.__final_states]
|
||||||
|
self.__minimize(eq_classes, [])
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
print(f" States => {self.__states}")
|
||||||
|
print(f" Initial states => {self.__initial_states}")
|
||||||
|
print(f" Final states => {self.__final_states}")
|
||||||
|
print("\n Transitions map => ")
|
||||||
|
for state, transition in self.__transitions.items():
|
||||||
|
print(f" {state} =>")
|
||||||
|
for symbol, dest in transition.items():
|
||||||
|
print(f" with {symbol} => {dest}")
|
||||||
|
|
||||||
|
def is_deterministic(self):
|
||||||
|
if len(self.__initial_states) > 1:
|
||||||
|
return False
|
||||||
|
for transition in self.__transitions.values():
|
||||||
|
for states in transition.values():
|
||||||
|
if len(states) != 1:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# ----------------- PRIVATE METHODS -------------------
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
# -------------------- READ METHODS -------------------
|
||||||
|
|
||||||
|
def __read(self, word, state):
|
||||||
|
if len(word) < 1 or word == lmbda:
|
||||||
|
if state in self.__final_states:
|
||||||
|
print("WORD ACCEPTED")
|
||||||
|
else:
|
||||||
|
print("WORD NOT ACCEPTED")
|
||||||
|
return
|
||||||
|
symbol = word[0]
|
||||||
|
if symbol not in self.__alphabet:
|
||||||
|
print(f"SYMBOL {symbol} NOT RECOGNIZED => WORD NOT ACCEPTED")
|
||||||
|
return
|
||||||
|
next_state = self.__transitions[state][symbol][0]
|
||||||
|
next_word = lmbda if len(word) <= 1 else word[1:]
|
||||||
|
print(
|
||||||
|
f"\t({state}, {word}) => ({next_state}, {next_word})")
|
||||||
|
self.__read(next_word, next_state)
|
||||||
|
|
||||||
|
# ---------------- MINIMIZE METHODS ------------------
|
||||||
|
|
||||||
|
def __minimize(self, current, previous):
|
||||||
|
if current == previous:
|
||||||
|
print(f"Final equivalence classes: {current}")
|
||||||
|
self.__update_states(current)
|
||||||
|
print("Minimization completed!")
|
||||||
|
return
|
||||||
|
equivalence = []
|
||||||
|
for s in current:
|
||||||
|
eq_class = s.copy()
|
||||||
|
while eq_class:
|
||||||
|
new_set = set()
|
||||||
|
r_state = eq_class.pop()
|
||||||
|
new_set.add(r_state)
|
||||||
|
for state in eq_class:
|
||||||
|
if self.__are_equivalent(r_state, state, current):
|
||||||
|
new_set.add(state)
|
||||||
|
eq_class -= new_set
|
||||||
|
equivalence.append(new_set)
|
||||||
|
self.__minimize(equivalence, current)
|
||||||
|
|
||||||
|
def __update_states(self, eq_classes):
|
||||||
|
for c in eq_classes:
|
||||||
|
if len(c) > 1:
|
||||||
|
new_state = c.pop()
|
||||||
|
print(f"States {c} minimized to => {new_state}")
|
||||||
|
self.__states -= c
|
||||||
|
self.__final_states -= c
|
||||||
|
for state in c:
|
||||||
|
del self.__transitions[state]
|
||||||
|
for transition in self.__transitions.values():
|
||||||
|
for dest in transition.values():
|
||||||
|
if dest[0] in c:
|
||||||
|
dest[0] = new_state
|
||||||
|
|
||||||
|
def __are_equivalent(self, state1, state2, groups):
|
||||||
|
""" Checks equivalence between two states
|
||||||
|
"""
|
||||||
|
for symbol in self.__alphabet:
|
||||||
|
s1 = self.__transitions[state1][symbol][0]
|
||||||
|
s2 = self.__transitions[state2][symbol][0]
|
||||||
|
for eq_class in groups:
|
||||||
|
if s1 in eq_class and s2 not in eq_class or s2 in eq_class and s1 not in eq_class:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# --------------- DETERMINIZE METHODS ----------------
|
||||||
|
|
||||||
|
def __get_next_state(self, curr_state, symbol):
|
||||||
|
new_state = set()
|
||||||
|
for state in curr_state:
|
||||||
|
new_state.update(set(self.__transitions[state][symbol]))
|
||||||
|
if len(new_state) == 0:
|
||||||
|
return empty_set
|
||||||
|
return tuple(new_state)
|
||||||
|
|
||||||
|
def __add_empty_set(self, transitions):
|
||||||
|
transitions[empty_set] = dict()
|
||||||
|
for letter in self.__alphabet:
|
||||||
|
transitions[empty_set][letter] = [empty_set]
|
||||||
|
|
||||||
|
def __is_final_state(self, t):
|
||||||
|
for elem in t:
|
||||||
|
if elem in self.__final_states:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ------------ ASSERTS --------------
|
||||||
|
def __assert_states(self, states):
|
||||||
|
if not isinstance(states, dict):
|
||||||
|
raise TypeError("Bad states type, has to be a map")
|
||||||
|
has_initial = False
|
||||||
|
has_final = False
|
||||||
|
for value in states.values():
|
||||||
|
if not isinstance(value, list):
|
||||||
|
raise TypeError("Bad states value, has to be a list")
|
||||||
|
if 'I' in value:
|
||||||
|
has_initial = True
|
||||||
|
if 'F' in value:
|
||||||
|
has_final = True
|
||||||
|
if not has_initial:
|
||||||
|
raise ValueError("States map doesn't has an initial state")
|
||||||
|
if not has_final:
|
||||||
|
raise ValueError("States map does not has a final state")
|
||||||
|
|
||||||
|
def __assert_alphabet(self, alphabet):
|
||||||
|
if not isinstance(alphabet, list):
|
||||||
|
raise TypeError("Bad alphabet type, has to be a list")
|
||||||
|
|
||||||
|
def __assert_transitions(self, transitions, alphabet, states):
|
||||||
|
if not isinstance(transitions, dict):
|
||||||
|
raise TypeError("Bad transitions format, has to be a map")
|
||||||
|
# Check if each state is defined in transitions map
|
||||||
|
for s in states:
|
||||||
|
if s not in transitions:
|
||||||
|
raise ValueError(f"State {s} not defined on transitions table")
|
||||||
|
# Check the transitions map format
|
||||||
|
for state in transitions:
|
||||||
|
# Check if each state is in the states map
|
||||||
|
if state not in states:
|
||||||
|
raise ValueError(
|
||||||
|
f"State {state} in transitions map not defined in states map")
|
||||||
|
# Check the transition object type
|
||||||
|
transition = transitions[state]
|
||||||
|
if not isinstance(transition, dict):
|
||||||
|
raise TypeError(
|
||||||
|
f"Transaction value {transition} has to be a symbol-states map")
|
||||||
|
# Check if each state has defined a behaviour for each symbol in the alphabet
|
||||||
|
for symbol in alphabet:
|
||||||
|
if symbol not in transition.keys():
|
||||||
|
raise ValueError(
|
||||||
|
f"Symbol {symbol} behaviour not defined in state {state}, each symbol has to be defined even if its value is an empty list.")
|
||||||
|
# Check the transition map content
|
||||||
|
for symbol, dest in transition.items():
|
||||||
|
# Check if each symbol is in the alphabet
|
||||||
|
if symbol not in alphabet:
|
||||||
|
raise ValueError(
|
||||||
|
f"Symbol {symbol} in state {state} transition is not in the alphabet")
|
||||||
|
# Check the destination states object type
|
||||||
|
if not isinstance(dest, Iterable):
|
||||||
|
raise TypeError(
|
||||||
|
f"Value {dest} in transitions table has to be an Iterable")
|
||||||
|
# Check if each state in destination list is in the states map
|
||||||
|
for s in dest:
|
||||||
|
if s not in states:
|
||||||
|
raise ValueError(
|
||||||
|
f"State {s} in {dest} not in states map")
|
||||||
60
python-lab/Finite-Automatons-Computation/src/main.py
Normal file
60
python-lab/Finite-Automatons-Computation/src/main.py
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
from automaton import FSM
|
||||||
|
from os import system, name
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def clear():
|
||||||
|
# for windows
|
||||||
|
if name == 'nt':
|
||||||
|
system('cls')
|
||||||
|
# for mac and linux(here, os.name is 'posix')
|
||||||
|
else:
|
||||||
|
system('clear')
|
||||||
|
|
||||||
|
|
||||||
|
def show_options():
|
||||||
|
print("D => Determinize automat")
|
||||||
|
print("M => Minimize automat")
|
||||||
|
print("read => Read a word")
|
||||||
|
print("show => Show automat")
|
||||||
|
print("clear => Clear screen")
|
||||||
|
print("help => Show commands")
|
||||||
|
print("quit => Close program")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
filename = input("Enter the automaton json filepath: ")
|
||||||
|
fp = open(filename, 'r')
|
||||||
|
automaton_json = json.load(fp)
|
||||||
|
automat = FSM(automaton_json)
|
||||||
|
show_options()
|
||||||
|
while True:
|
||||||
|
option = input(">> ").lower()
|
||||||
|
if option == 'd':
|
||||||
|
if automat.is_deterministic():
|
||||||
|
print("This automaton is already determinized")
|
||||||
|
continue
|
||||||
|
automat.determinize()
|
||||||
|
elif option == 'm':
|
||||||
|
automat.minimize()
|
||||||
|
elif option == 'read':
|
||||||
|
word = input("Enter the word you want to read: ")
|
||||||
|
automat.read(word)
|
||||||
|
elif option == 'show':
|
||||||
|
automat.show()
|
||||||
|
elif option == 'clear':
|
||||||
|
clear()
|
||||||
|
elif option == 'help':
|
||||||
|
show_options()
|
||||||
|
elif option == 'quit':
|
||||||
|
print("Bye!")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("Command not recognized")
|
||||||
|
except OSError as err:
|
||||||
|
print("OSError:", err)
|
||||||
|
except ValueError as err:
|
||||||
|
print("ValueError:", err)
|
||||||
|
except TypeError as err:
|
||||||
|
print("TypeError:", err)
|
||||||
Loading…
Reference in a new issue