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