Property-based testing utilities for finite automata and context-free grammars.
Project description
pbt4automata
pbt4automata provides tools to construct finite automata and context-free grammars in Python and validate their behavior with property-based tests powered by Hypothesis.
Installation
pip install -e .
Examples
Deterministic Finite Automata
Testing a DFA against a rule
The following example tests a DFA that accepts all strings that contain the substring "010" or "100".
from pbt4automata import DFA
automaton = DFA(
states=["q0", "q1", "q2", "q3", "q4", "q5"],
alphabet="01",
transition_function={
("q0", "0"): "q1",
("q0", "1"): "q4",
("q1", "0"): "q1",
("q1", "1"): "q2",
("q2", "0"): "q3",
("q2", "1"): "q4",
("q3", "0"): "q3",
("q3", "1"): "q3",
("q4", "0"): "q5",
("q4", "1"): "q4",
("q5", "0"): "q3",
("q5", "1"): "q2",
},
start_state="q0",
accept_states=["q3"],
)
result = automaton.test("[01]*(010|100)[01]*")
if result is True:
print("Success!")
else:
print("Counterexample:", result)
You can also pass a function of type Callable[[str], bool] to automaton.test(...) instead of a regex.
Testing two DFAs for equivalence
from pbt4automata import Automaton, DFA
automata1 = DFA(
...
)
automata2 = DFA(
...
)
result = Automaton.test_equivalence(automata1, automata2)
if result is True:
print("Success!")
else:
print("Counterexample:", repr(result))
Nondeterministic Finite Automata
Testing an NFA against a rule
NFAs support nondeterministic transitions (multiple possible next states for a given state and symbol) as well as epsilon (ε) transitions. The transition function maps (state, symbol) pairs to sets of states; use None as the symbol for ε-transitions. Unlike DFAs, the transition function may be partial.
The following example tests an NFA that accepts all strings over {0, 1} that end with the substring "01".
from pbt4automata import NFA
nfa = NFA(
states=["q0", "q1", "q2"],
alphabet="01",
transition_function={
("q0", "0"): {"q0", "q1"}, # nondeterministically guess start of "01"
("q0", "1"): {"q0"},
("q1", "1"): {"q2"},
},
start_state="q0",
accept_states=["q2"],
)
result = nfa.test("[01]*01")
if result is True:
print("Success!")
else:
print("Counterexample:", result)
You can also pass a function of type Callable[[str], bool] to nfa.test(...) instead of a regex.
NFA with epsilon transitions
from pbt4automata import NFA
# Accepts "a" or "ab"
nfa = NFA(
states=["q0", "q1", "q2", "q3"],
alphabet="ab",
transition_function={
("q0", "a"): {"q1"},
("q1", None): {"q2"}, # ε-transition: q1 is also effectively q2
("q1", "b"): {"q3"},
},
start_state="q0",
accept_states=["q2", "q3"],
)
Testing an NFA for equivalence with another automaton
Automaton.test_equivalence works with any mix of DFA and NFA objects sharing the same alphabet.
from pbt4automata import Automaton, DFA, NFA
nfa = NFA(...)
dfa = DFA(...)
result = Automaton.test_equivalence(nfa, dfa)
if result is True:
print("Success!")
else:
print("Counterexample:", repr(result))
Context-Free Grammars
Testing a CFG against a rule
The following example tests a CFG that generates all non-empty strings of balanced parentheses.
from pbt4automata import Grammar
grammar = Grammar(
terminals="()",
nonterminals="S",
productions={
"S": ["(S)", "SS", "()"],
},
start_symbol="S",
)
def check_balance(input_string: str) -> bool:
if input_string == "":
return False
s = 0
for c in input_string:
if c == "(":
s += 1
elif c == ")":
s -= 1
if s < 0:
return False
return s == 0
result = grammar.test(check_balance)
if result is True:
print("Success!")
else:
print("Counterexample:", result)
You can also pass a function of type Callable[[str], bool] to grammar.test(...).
Parsing strings
from pbt4automata import Grammar
# Grammar for "a^n b^n" (n ≥ 1): S → aSb | ab
grammar = Grammar(
terminals="ab",
nonterminals="S",
productions={
"S": ["aSb", "ab"],
},
start_symbol="S",
)
print(grammar.parse("ab")) # True
print(grammar.parse("aabb")) # True
print(grammar.parse("aaabbb")) # True
print(grammar.parse("aab")) # False
Development
Install dev dependencies and run tests:
pip install -e ".[dev]"
pytest -v
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pbt4automata-0.2.1.tar.gz.
File metadata
- Download URL: pbt4automata-0.2.1.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88e09d8e7625e5c14c0bf99dd2ddb19f2534accb9ffcd3005d28923104edd1de
|
|
| MD5 |
2e65c75baa20db71747b7e86da1d707b
|
|
| BLAKE2b-256 |
5a0e0a38ea874a8a4f75b6ece90aca2059cb32dae260fd6fcd79e18ad3d61311
|
Provenance
The following attestation bundles were made for pbt4automata-0.2.1.tar.gz:
Publisher:
python-publish.yml on mrigankpawagi/pbt4automata
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pbt4automata-0.2.1.tar.gz -
Subject digest:
88e09d8e7625e5c14c0bf99dd2ddb19f2534accb9ffcd3005d28923104edd1de - Sigstore transparency entry: 1155091974
- Sigstore integration time:
-
Permalink:
mrigankpawagi/pbt4automata@d023be9e741680ca31d3df04796b8f2445ebc143 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/mrigankpawagi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@d023be9e741680ca31d3df04796b8f2445ebc143 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pbt4automata-0.2.1-py3-none-any.whl.
File metadata
- Download URL: pbt4automata-0.2.1-py3-none-any.whl
- Upload date:
- Size: 9.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4026072772a155b3801219f0b2b57f28c14962abe75c55deddf265c0b6359148
|
|
| MD5 |
a8c9396695860824f61311e9bdbe2042
|
|
| BLAKE2b-256 |
86c12955d10752a65a9339210bb2ea298c4cf4f712644ffdc6b4dbccb6631fd3
|
Provenance
The following attestation bundles were made for pbt4automata-0.2.1-py3-none-any.whl:
Publisher:
python-publish.yml on mrigankpawagi/pbt4automata
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pbt4automata-0.2.1-py3-none-any.whl -
Subject digest:
4026072772a155b3801219f0b2b57f28c14962abe75c55deddf265c0b6359148 - Sigstore transparency entry: 1155091975
- Sigstore integration time:
-
Permalink:
mrigankpawagi/pbt4automata@d023be9e741680ca31d3df04796b8f2445ebc143 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/mrigankpawagi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@d023be9e741680ca31d3df04796b8f2445ebc143 -
Trigger Event:
release
-
Statement type: