#python #solver #finite-automata #model-checking
#питон #решатель #конечные автоматы #проверка модели
Вопрос:
У меня есть функция, которая определяет язык, давайте вызовем L, эта функция получает слово и возвращает True или False.
У меня также есть детерминированные конечные осенние данные, которые предполагают принимать слова, которые есть на языке, и сожалеть о словах, которых нет на языке L.
Моя миссия состоит в том, чтобы получить контрпример, который будет различать функцию dfa и функцию python.
Интересно, может ли перекрестие быть полезным для этой задачи.
Я ожидаю чего-то вроде:
counterexmaple = checker(dfa, func)
Спасибо
Ответ №1:
Краткие сведения
Возможно, вы сможете использовать перекрестие для решения такого рода проблем. Однако выполнение детерминированных конечных автоматов (DFA) будет связано с большим количеством ветвистых действий, и CrossHair не очень хорошо работает в этой ситуации. В большинстве случаев вам может быть лучше использовать рандомизированный подход к тестированию с гипотезой. Я опишу оба подхода.
Предварительные мероприятия
Во-первых, вы захотите иметь возможность выразить свой DFA на python, чтобы сравнить реализации. Вот один из примеров:
from typing import Tuple, Dict
# We construct a DFA that accepts any string that ends
# with "abc":
_TRANSITION_TABLE: Dict[Tuple[int, str], int] = {
# state #0: we have not yet seen "a" (initial state)
(0, 'a'): 1,
# state #1: we've seen "a"
(1, 'a'): 1,
(1, 'b'): 2,
# state #2: we've seen "ab"
(2, 'a'): 1,
(2, 'c'): 3,
# state #3: we've seen "abc" (final state)
(3, 'a'): 1,
}
def dfa_checker(s: str) -> bool:
state = 0
for char in s:
state = _TRANSITION_TABLE.get((state, char), 0)
return state == 3
def correct_custom_checker(s: str) -> bool:
return s.endswith("abc")
def incorrect_custom_checker(s: str) -> bool:
return s.endswith("bc")
Решение перекрестия
Вы можете предоставить пользовательской реализации контракт, в котором указано, что его результат совпадает с DFA:
def incorrect_custom_checker(s: str) -> bool:
''' post: __return__ == dfa_checker(s) '''
return bool(re.fullmatch('[abc]*', s) and s.endswith("bc"))
Хотя это и не требуется для реальной функции, добавление регулярного выражения для нашего алфавита (abc) помогает CrossHair найти решение. Теперь у нас может быть попытка CrossHair опровергнуть контракт:
$ crosshair check example.py
example.py:29:error:false when calling incorrect_custom_checker(s = 'bc') (which returns True)
И он находит контрпример «bc», который принимается incorrect_custom_checker(), но отклоняется DFA.
Кроме того, существует совершенно новая, в значительной степени недокументированная команда crosshair, которая делает подобные вещи еще проще. Вы можете сравнить любые две произвольные функции python, используя:
$ crosshair diffbehavior example.incorrect_custom_checker example.dfa_checker
given: (s='bc')
- returns: True
returns: False
Если вам нужно сделать это полностью программно, вы можете обратиться к внутренним устройствам CrossHair, которые делают это здесь. Этот подход будет нарушен по мере развития кодовой базы CrossHair, но я включил его здесь для полноты картины.
Гипотетическое решение
Как я упоминал ранее, выполнение большого количества рандомизированных тестов, вероятно, будет работать лучше для вас. Вот способ сделать это в гипотезе:
import hypothesis
from hypothesis.strategies import text
@hypothesis.given(text(alphabet="abc"))
def test_checkers_equivalent(s: str) -> None:
assert dfa_checker(s) == incorrect_custom_checker(s)
Запустив pytest example.py
, вы найдете тот же контрпример «bc».
Комментарии:
1. Спасибо за подробный ответ, согласно гипотетическому решению, есть ли способ запустить его не как тест, а при стандартном запуске проекта?
2. К сожалению, я не знаю способа запустить встроенную гипотезу. Может быть уместно в качестве другого вопроса о переполнении стека? Сообщество гипотез довольно активное и дружелюбное.
3. согласно тому, что вы написали «Если вам нужно сделать это полностью программно, вы могли бы обратиться к внутренним устройствам CrossHair, которые делают это здесь» Интересно, можно ли добавить опцию «pre:» в AnalysisOptions Спасибо