diff --git a/examples/detector.py b/examples/detector.py new file mode 100644 index 0000000..06a7a62 --- /dev/null +++ b/examples/detector.py @@ -0,0 +1,52 @@ +from typing import TypedDict + +from snanosm.mealy import Machine, TransitionInputEnum + + +class Context(TypedDict): + count: int + position: int + matches: int + + +def dinc(context: Context): + context["count"] += 1 + +def dset(context: Context): + context["position"] = context["count"] + context["count"] += 1 + +def dprn(context: Context): + context["count"] += 1 + print(f"SUBSTRING FOUND AT POSITION: {context['position']}") + context["matches"] += 1 + + +# Detects the sequence AB in the string, printing the position and returning the amount of matches +def detector(input_string: str) -> int: + initial_context: Context = { + "count": 0, + "position": 0, + "matches": 0, + } + m = Machine(initial_context) + m.add_state("Q0", True, False) + m.add_state("Q1", False, False) + m.add_transition("A", "Q0", "Q1", lambda context: dset(context)) + m.add_transition(TransitionInputEnum.MATCH_REST, "Q0", "Q0", lambda context: dinc(context)) + m.add_transition("B", "Q1", "Q0", lambda context: dprn(context)) + m.add_transition(TransitionInputEnum.MATCH_REST, "Q1", "Q0", lambda context: dinc(context)) + for c in input_string: + m.process_input(c) + return initial_context["matches"] + +if __name__ == "__main__": + print("== 1 ==") + n = detector("AAAAAAABAAAAAB") + print(f"Matches: {n}") + print("== 2 ==") + n = detector("AAAA") + print(f"Matches: {n}") + print("== 3 ==") + n = detector("ABCCBBACAB") + print(f"Matches: {n}") diff --git a/src/snanosm/mealy.py b/src/snanosm/mealy.py index 35cb985..6ca1794 100644 --- a/src/snanosm/mealy.py +++ b/src/snanosm/mealy.py @@ -32,7 +32,7 @@ class State: class Transition(Generic[TransitionInput]): def __init__(self, transition_input: TransitionInput, origin_name: str, destination_name: str, - output_function: Callable[[Optional[object]], None]) -> None: + output_function: Optional[Callable[[Optional[object]], None]]) -> None: self.__transition_input = transition_input self.__origin_name = origin_name self.__destination_name = destination_name @@ -40,7 +40,8 @@ class Transition(Generic[TransitionInput]): self.__output_function = output_function def execute_output(self, context): - self.__output_function(context) + if self.__output_function is not None: + self.__output_function(context) def get_destination_name_hash(self) -> int: return self.__destination_name_hash @@ -63,7 +64,7 @@ class Machine(Generic[Input]): self.__context = initial_context def add_transition(self, transition_input: TransitionInput, origin_name: str, destination_name: str, - output_function: Callable[[Optional[object]], None]) -> None: + output_function: Optional[Callable[[Optional[object]], None]]) -> None: ho = hash(origin_name) if ho not in self.__states.keys(): raise ValueError(f"Origin state {origin_name} does not exist.")