Следующее кодирование может быть использован с любым графом с N
узлов и M
краев. Используются переменные (N+1)*M
и 2*M*M
3-SAT. This ipython notebook демонстрирует кодировку, сравнивая результаты SAT-решения (UNSAT, если есть цикл, SAT в противном случае) с результатами алгоритма поиска в прямом цикле.
Отказ от ответственности: эта кодировка является моим специальным решением проблемы. Я уверен, что это правильно, но я не знаю, как он сравнивает производительность с другими кодировками для этой проблемы. Поскольку мое решение работает с любым графиком его следует ожидать, что лучшее решение существует, который использует некоторые из свойств класса графов ОР заинтересован в
Переменные:.
у меня есть одна переменных для каждого ребра. Край является «активным» или «использованным», если установлена соответствующая переменная. В моей эталонной реализации ребро имеют индексы 0..(M-1)
и эти переменные имеют индексы 1..M
:
def edge_state_var(edge_idx):
assert 0 <= edge_idx < M
return 1 + edge_idx
Тогда у меня есть M
бит широкого переменное состояния для каждого ребра, или в общей сложности N*M
государственных бит (узлы и биты также с использованием нуль индексация):
def node_state_var(node_idx, bit_idx):
assert 0 <= node_idx < N
assert 0 <= bit_idx < M
return 1 + M + node_idx*M + bit_idx
Статья:
Когда край активен, он связывает т он связывает переменные двух узлов, с которыми он соединяется. Биты состояния с тем же индексом, что и узел, должны быть разными с обеих сторон, а остальные бит состояния должны быть равны их соответствующему партнеру на другом узле. В коде Python:
# which edge connects which nodes
connectivity = [
(0, 1), # edge E0
(1, 2), # edge E1
(2, 3), # edge E2
(0, 4), # edge E3
...
]
cnf = list()
for i in range(M):
eb = edge_state_var(i)
p, q = connectivity[i]
for k in range(M):
pb = node_state_var(p, k)
qb = node_state_var(q, k)
if k == i:
# eb -> (pb != qb)
cnf.append([-eb, -pb, -qb])
cnf.append([-eb, +pb, +qb])
else:
# eb -> (pb == qb)
cnf.append([-eb, -pb, +qb])
cnf.append([-eb, +pb, -qb])
Таким образом, в основном, каждое ребро пытается сегмент графика он является частью в половину, которая находится на одной стороне краев и имеет все государственные биты, соответствующие множеству краев к 1 и которая находится на другой стороне края и имеет бит состояния, соответствующий краю, установленному в 0. Это невозможно для цикла, в котором все узлы в цикле могут быть достигнуты с обеих сторон каждого ребра в цикле.
Ваша проблема - это вариация проблемы [неориентированного гамильтонова пути] (http://en.wikipedia.org/wiki/Hamiltonian_path_problem). Это проблема NP, поэтому должно быть сокращение полиномиального времени от нее до SAT. Перечисление всех возможных циклов и запрещение их создает список, который растет экспоненциально по мере увеличения количества ребер, поэтому вам нужен другой подход. Вы должны иметь возможность немного изменить сокращение [Гамильтониан-SAT на этой странице] (http://cs.fit.edu/~wds/classes/complexity/lct/complete/), чтобы создать экземпляр SAT, который является выполнимым если есть петли любого размера. –
Спасибо за ваш ответ. Если я исправлю размер проблемы только для сети 4x4, то будет ли это просто? – Raj
На самом деле, это не проблема Гамильтонова пути. Это потому, что я не посещаю каждый узел. Вместо этого я посещаю некоторые узлы, которые образуют путь от исходного узла до целевого узла. Некоторые узлы и ссылки могут оставаться неактивными для заданного пути. – Raj