Таблицы истинности
Дана логическая функция и кусок её таблицы, столбцы не подписаны. Надо понять, какой столбец какой переменной соответствует. Один шаблон кода решает почти всё, думать нужно только о том, как без ошибок записать функцию.
- 1Что проверяет номер
- 2Знаки логики на Python
- 3Шаблон: F одинаковая во всех строках
- 4Разные значения F и две функции
- 5Как это решают руками
- 6Ловушки перед экзаменом
- 7Домашка
Что проверяет номер
Дана функция F от переменных x, y, z, w и несколько строк её таблицы истинности. Столбцы переменных не подписаны, часть клеток пустая. Нужно понять, какой столбец какой переменной соответствует. Ответ это буквы в порядке столбцов, например zxwy.
Вид задачи легко определить по последнему столбцу:
В столбце F только нули или только единицы. Самый частый вид.
Строки: 1 0 _ 0 | 0, _ 1 0 _ | 0, 0 _ 0 0 | 0.
В столбце F есть и 0, и 1, либо справа сразу два столбца значений: F1 и F2.
Строки: 0 0 _ 1 | 1, 1 _ 1 1 | 0, 1 0 _ 1 | 1.
Бывает ещё фрагмент совсем без пустых клеток. Это та же задача, только перебирать заполнение не нужно.
Все виды решаются одним кодом. Компьютер пробует все способы заполнить пустые клетки и все порядки столбцов и печатает тот порядок, который подошёл.
Знаки логики на Python
Сначала условие надо перевести на Python. Таблица короткая, и её стоит выучить.
| В условии | На Python | Смысл |
|---|---|---|
| ¬a | not a | отрицание |
| a ∧ b | a and b | оба истинны |
| a ∨ b | a or b | хотя бы один истинен |
| a → b | a <= b | ложно только при 1 → 0 |
| a ≡ b | a == b | значения совпадают |
| a ⊕ b, a ≢ b | a != b | значения разные |
Запусти и убедись, что <= ведёт себя как импликация. Ноль получается только в строке 1 0:
print('a b a→b') for a in 0, 1: for b in 0, 1: print(a, b, ' ', int(a <= b))
Как записать функцию без ошибок
- Скопируй выражение из условия к себе в код, чтобы не перепечатывать.
- Замени знаки на Python, не трогая скобки.
- Сверь скобки с условием один в один.
- Перед каждой скобкой с отрицанием оставь
not:not (y == z).
Например, F = ((x → y) ∧ ¬z) ∨ (w ≡ x) превращается в такую функцию:
def f(x, y, z, w): return ((x <= y) and (not z)) or (w == x)
Запись x <= y == z Python понимает как (x <= y) and (y == z), а совсем не как (x <= y) == z. Такая цепочка сравнений молча даёт неверный ответ. Каждую импликацию и эквивалентность бери в свои скобки.
Посмотри на это сам. Две записи ниже выглядят похоже, но на трёх наборах из восьми расходятся:
from itertools import product for x, y, z in product([0, 1], repeat=3): wrong = x <= y == z # цепочка: (x <= y) and (y == z) right = (x <= y) == z # то, что написано в условии print(x, y, z, int(wrong), int(right), '' if wrong == right else '<- разные')
Дана функция F = (x → y) ≡ z. На скольких наборах из восьми F равна 1? Напиши её со скобками и посчитай.
from itertools import product
k = 0
for x, y, z in product([0, 1], repeat=3):
if ...: # запиши функцию вместо многоточия
k += 1
print(k)
Шаблон: F одинаковая во всех строках
Разберём шаблон на примере. Функция F = ((x → y) ∧ ¬z) ∨ (w ≡ x), дан фрагмент из трёх различных строк. Пустая клетка это значение, которое мы не знаем.
| F | ||||
|---|---|---|---|---|
| 1 | 0 | 0 | 0 | |
| 1 | 0 | 0 | ||
| 0 | 0 | 0 | 0 |
План такой:
- Пишем функцию
f(x, y, z, w). - Переписываем таблицу в код. Каждая пустая клетка становится своей переменной: a, b, c, d. Последнее число в строке это значение F.
productперебирает, чем заполнить пустые клетки.- Проверяем, что строки получились разные. В условии сказано, что строки различны.
permutations('xyzw')перебирает, какой столбец какая переменная.- Если на всех строках F совпала со значением в таблице, печатаем порядок.
from itertools import product, permutations def f(x, y, z, w): return ((x <= y) and (not z)) or (w == x) for a, b, c, d in product([0, 1], repeat=4): # 4 пустые клетки t = ( (1, 0, a, 0, 0), # последнее число — значение F (b, 1, 0, c, 0), (0, d, 0, 0, 0), ) if len(t) == len(set(t)): # строки должны быть разными for p in permutations('xyzw'): # p — порядок столбцов, например ('z','x','w','y') if all(f(**dict(zip(p, line))) == line[-1] for line in t): print(''.join(p))
Ответ zxwy. Он напечатается два раза, потому что подходит при двух разных заполнениях пустых клеток. Это нормально. Вот если напечатались разные порядки, то ошибка в функции или таблице.
Что происходит в длинной строке
Строка с all выглядит страшно, но разбирается по кускам:
zip(p, line)склеивает буквы порядка с числами строки:('z', 1),('x', 0)и так далее. Последнее число, значение F, отбрасывается само, потому что букв всего четыре.dict(...)превращает пары в словарь{'z': 1, 'x': 0, …}.f(**словарь)подставляет значения по именам:f(z=1, x=0, …).all(...)даёт True, только если условие выполнилось на всех строках.
Если так понятнее, ту же проверку можно написать длиннее, без ** и all. Ответ будет тот же:
for p in permutations('xyzw'): ok = True for line in t: v = dict(zip(p, line)) # {'z': 1, 'x': 0, ...} if f(v['x'], v['y'], v['z'], v['w']) != line[-1]: ok = False if ok: print(''.join(p))
Проверку len(t) == len(set(t)) легко забыть. Убери её в примере выше и запусти: появится лишний ответ wxzy, и непонятно, какой вписывать. Пишем эту проверку всегда.
Сколько переменных в product, столько и пустых клеток. Если пустых клеток нет, product и проверка различия не нужны, остаётся только цикл по permutations.
Разные значения F и две функции
В столбце F и 0, и 1
Код менять не надо. Мы и так сравниваем F со значением своей строки, line[-1], а не с константой. Поэтому шаблон работает сразу. Попробуй на задаче.
F = (x ∨ ¬y) ∧ (z → w) ∧ (¬w ∨ x). Фрагмент из трёх различных строк, значения F разные. Какой столбец какая переменная?
| F | ||||
|---|---|---|---|---|
| 0 | 0 | 1 | 1 | |
| 1 | 1 | 1 | 0 | |
| 1 | 0 | 1 | 1 |
from itertools import product, permutations
def f(x, y, z, w):
return ... # запиши функцию
for a, b, c in product([0, 1], repeat=3): # 3 пустые клетки
t = (
(0, 0, a, 1, 1),
(1, b, 1, 1, 0),
(1, 0, c, 1, 1),
)
if len(t) == len(set(t)):
for p in permutations('xyzw'):
if all(f(**dict(zip(p, line))) == line[-1] for line in t):
print(''.join(p))
Две функции в одной таблице
Справа два столбца значений, F1 и F2. Пишем две функции и проверяем обе. Значение F1 теперь предпоследнее в строке, line[-2], а F2 последнее, line[-1]. Лишние числа zip опять отбросит сам.
from itertools import product, permutations def f1(x, y, z, w): return (x <= y) or (z and (not w)) def f2(x, y, z, w): return (y == w) <= (x or z) for a, b, c, d in product([0, 1], repeat=4): t = ( (1, a, 0, b, 1, 0), # два последних числа — F1 и F2 (0, 0, c, 0, 1, 0), (1, 1, 0, d, 0, 1), ) if len(t) == len(set(t)): for p in permutations('xyzw'): if all(f1(**dict(zip(p, line))) == line[-2] and f2(**dict(zip(p, line))) == line[-1] for line in t): print(''.join(p))
Ответ wxzy.
Как это решают руками
На экзамене руками долго, основной способ это код. Но идею стоит знать: она помогает понять, что вообще делает перебор, и проверить ответ.
Руками ищут вынужденные значения:
- если F = 0, а F это дизъюнкция (∨) нескольких скобок, то каждая скобка равна 0;
- если F = 1, а F это конъюнкция (∧), то каждая скобка равна 1.
Из этого получаются условия вида «x и w в каждой строке разные» или «z везде равна 1». Дальше ищем столбцы, которые подходят под эти условия во всех строках, и начинаем со строк, где пустых клеток меньше всего.
Пример из раздела 3 начинается так. F = 0, значит, (w ≡ x) = 0, и в каждой строке x и w противоположны. В третьей строке нули стоят в первом, третьем и четвёртом столбцах. Значит, одна из букв x и w точно во втором столбце.
Можно ещё вывести все строки, где F = 0, и сравнить их с фрагментом глазами:
from itertools import product print('x y z w') for x, y, z, w in product([0, 1], repeat=4): if not (((x <= y) and (not z)) or (w == x)): print(x, y, z, w)
Ловушки перед экзаменом
| Ловушка | Как не попасться |
|---|---|
Цепочка x <= y == z | Каждую импликацию и эквивалентность в свои скобки |
→ записали как >= | a → b это a <= b |
| Нет проверки на разные строки | Всегда пиши len(t) == len(set(t)) |
| Сравнили F с константой | Сравнивай с line[-1], тогда код подойдёт для любых значений |
| Две функции: перепутали столбцы | Если F1 левее, то F1 это line[-2], а F2 это line[-1] |
Буквы в permutations | Те же, что в def f(...), порядок внутри строки неважен |
| Ответ напечатался несколько раз | Это нормально, если порядок один и тот же. Разные порядки означают ошибку |
| Ответ с пробелами | Буквы подряд: zxwy |
Домашка
Шесть задач с настоящих экзаменов и из банка ФИПИ. Решай прямо здесь: кнопка «Решать здесь» открывает редактор, а код каждой задачи сохраняется.
Перед тем как писать код, сделай три вещи:
- перепиши функцию со всеми скобками и сверь её с условием;
- посчитай пустые клетки, столько переменных будет в
product; - посмотри, что стоит в столбце F в этой задаче.
В первой задаче внутри функции и эквивалентность, и импликация, скобки тут особенно важны. В пятой значение F равно 1, а не 0, но код от этого не меняется. Ответ везде это четыре маленькие буквы подряд.
Ещё задачи этого вида лежат в разделе «Задания», №2.
Задачи «Попробуй сам» учебные, в домашке задачи с настоящих экзаменов и из банка ФИПИ. Код в блоках можно менять и запускать, он выполняется прямо в браузере.