Алгоритм Дэвиса – Путнэма – Логемана – Лавленда (DPLL) - это алгоритм поиска на основе обратного отслеживания для определения выполнимости логических формул высказываний в конъюнктивной нормальной форме, также известный как проблема выполнимости или SAT.
Любая логическая формула может быть выражена в конъюнктивной нормальной форме (CNF), что означает соединение предложений, т. Е. (…) ^ (…) ^ (…)
где предложение является дизъюнкцией булевых переменных, т. Е. (A v B v C ’v D)
пример булевой формулы, выраженной в CNF:
(A v B v C) ^ (C ’v D) ^ (D’ v A)
и решение проблемы SAT означает поиск комбинации значений для переменных в формуле, которые удовлетворяют ей, например, A = 1, B = 0, C = 0, D = 0
Это проблема NP-Complete. На самом деле это первая проблема, доказанная NP-Complete Стивеном Куком и Леонидом Левиным
Конкретным типом проблемы SAT является 3-SAT, который представляет собой SAT, в котором все предложения имеют три переменные.
Алгоритм DPLL является способом решения проблемы SAT (которая практически зависит от твердости ввода), которая рекурсивно создает дерево потенциального решения
Предположим, вы хотите решить проблему 3-SAT следующим образом
(A v B v C) ^ (C ’v D v B) ^ (B v A’ v C) ^ (C ’v A’ v B ’)
если мы перечислим такие переменные, как A = 1 B = 2 C = 3 D = 4 и найдем отрицательные числа для отрицательных переменных, таких как A ’= -1, то такую же формулу можно написать на Python, например, так:
[[1,2,3], [- 3,4,2], [2, -1,3], [- 3, -1, -2]]
Теперь представьте, что вы создали дерево, в котором каждый узел состоит из частичного решения. В нашем примере мы также изобразили вектор предложений, удовлетворяемых решением
корневым узлом является [-1, -1, -1, -1], что означает, что никакие значения еще не были присвоены переменным ни 0, ни 1
на каждой итерации:
мы берем первое неудовлетворенное предложение, затем
если больше нет неназначенных переменных, которые мы можем использовать для удовлетворения этого условия, тогда в этой ветви дерева поиска не может быть допустимых решений, и алгоритм должен вернуть None
в противном случае мы берем первую неназначенную переменную и устанавливаем ее так, чтобы она удовлетворяла условию, и начинаем рекурсивно с шага 1. Если внутренний вызов алгоритма возвращает None, мы переворачиваем значение переменной так, чтобы она не удовлетворяла предложение и установите следующую неназначенную переменную, чтобы удовлетворить предложение. Если все три переменные были опробованы или для этого предложения больше нет неназначенной переменной, это означает, что в этой ветви нет допустимых решений, и алгоритм должен вернуть None
См. Следующий пример:
из корневого узла мы выбираем первую переменную (A) первого предложения (A v B v C) и устанавливаем ее так, чтобы она удовлетворяла предложению, тогда A = 1 (второй узел дерева поиска)
продолжить со вторым предложением, и мы выбираем первую неназначенную переменную (C) и устанавливаем ее так, чтобы она удовлетворяла предложению, что означает C = 0 (третий узел слева)
мы делаем то же самое для четвертого предложения (B v A ’v C) и устанавливаем B в 1
мы пытаемся сделать то же самое для последнего предложения, которое мы понимаем, что у нас больше нет неназначенных переменных, и предложение всегда ложно. Затем мы должны вернуться к предыдущей позиции в дереве поиска. Мы изменяем значение, которое мы присвоили B, и устанавливаем B на 0. Затем мы ищем другое неназначенное значение, которое может удовлетворить третье предложение, но его нет. Затем мы должны вернуться обратно ко второму узлу
Оказавшись там, мы должны перевернуть присвоение первой переменной (C), чтобы оно не удовлетворяло предложению, и установить следующую неназначенную переменную (D), чтобы удовлетворить ее (то есть C = 1 и D = 1 ). Это также удовлетворяет третьему пункту, который содержит C.
Последний пункт для удовлетворения (C ’v A ’v B’) имеет одну неназначенную переменную B, которую затем можно установить в 0 для удовлетворения условия.
В этой ссылке http://lowcoupling.com/post/72424308422/a-simple-3-sat-solver-using-dpll вы также можете найти код Python, реализующий его