sift

SAT-солвер (DPLL) с набором инструментов пропозициональной логики и парсером DIMACS, на Haskell. Решает реальные экземпляры и переводит формулы в КНФ (Цейтин).

sift
TL;DR

SAT-солвер на основе алгоритма DPLL, написанный на Haskell, плюс набор инструментов пропозициональной логики: парсер DIMACS и перевод формул в CNF методом Цейтина. Решает реальные экземпляры.

Обзор

sift - это SAT-солвер на основе алгоритма DPLL, написанный на Haskell, вместе с набором инструментов пропозициональной логики: парсером формата DIMACS и переводом формул в форму CNF методом Цейтина. Это не упражнение на бумаге - он решает реальные экземпляры.

SAT - одна из тех задач, что соединяют кажущуюся простоту с огромной глубиной. Вопрос звучит невинно, а ответ на него способен решать задачи из совершенно иных областей. Этот проект касается именно этого ядра, и со стороны, которая заставляет понять, почему солвер вообще работает.

SAT спрашивает вещь на вид банальную: можно ли подобрать логические значения так, чтобы вся формула была истинной? Банально до момента, когда переменных сотни, а от ответа зависят планирование, верификация схем или решение головоломки. SAT-солвер сидит под многими трудными задачами, которые сначала переводят на его язык.

Стандартный вход - формат DIMACS - каждая строка это дизъюнкт, числа это переменные, минус это отрицание, ноль завершает дизъюнкт. Простой текст, который умеет кодировать удивительно трудные вопросы.

example.cnf · text
p cnf 3 2
1 -3 0
2 3 -1 0

Как работает DPLL

DPLL - это умный поиск с возвратом. Вместо того чтобы перебирать все комбинации, на каждом шаге он выбирает переменную, задаёт ей значение и следит за двумя сокращениями: если у дизъюнкта только один неразрешённый литерал, его значение вынуждено; если переменная всегда встречается в одной и той же форме, её можно сразу задать.

Именно эти два сокращения делают разницу между секундой и вечностью. Без них солвер блуждает по дереву всех возможностей; с ними целые поддеревья отпадают, ещё не будучи посещёнными. Правильно их реализовать - сердце всего солвера.

Цейтин: почему CNF не взрывается

DPLL требует формулу в форме CNF, но не всякая формула уже такова. Наивное преобразование способно раздуть её размер экспоненциально, превращая маленькую задачу в гигантскую ещё до старта солвера. Метод Цейтина вводит вспомогательные переменные и удерживает рост линейным.

Размер формулы после преобразования (ориентировочно)

Наивное преобразование
1000
Метод Цейтина
40
i
Примечание

Метод Цейтина - один из тех приёмов, что выглядят как магия, пока не поймёте, почему они работают. Он добавляет вспомогательные переменные, которые с виду усложняют формулу, а на деле спасают её размер - без них наивное преобразование способно расти экспоненциально.

Эффект: солвер, который действительно решает

На выходе - работающий солвер, который берёт реальные экземпляры в формате DIMACS и возвращает ответ, а по дороге переводит любую формулу в CNF, не раздувая её размер. Написан на Haskell, потому что сопоставление с образцом и типы, стерегущие правильность, делают так, что логика читается почти как математика. Маленький проект, который касается очень глубокой части информатики - и по-настоящему её решает.

Больше проектов

Другие работы из той же категории - посмотрите, как мы решаем похожие задачи.

Есть похожий проект?

Напишите нам - смета бесплатна и приходит в течение часа.