Я пытаюсь закодировать Проблема назначения частот (точнее, Экземпляр 6) через Z3 в Python, используя информацию из статьи О SAT Modulo Theories и задачах оптимизации , который я постараюсь кратко описать.
Проблема состоит в назначении частот парам радиолиний таким образом, чтобы были соблюдены некоторые ограничения. Каждую частоту следует выбирать из конечного набора Di , и ограничения имеют вид:
|fi − fj| > k (soft, comes with a cost associated )
|fi - fj| = d (hard)
fi = pi (pre-assignment, hard)
В документе описывается, как домены можно рассматривать как несвязное объединение четырех наборов:
{2 + 14m | 1 ≤ m ≤ 11}
{2 + 14m | 18 ≤ m ≤ 28}
{8 + 14km | 29 ≤ m ≤ 39}
{8 + 14m | 46 ≤ m ≤ 56}
И что мы можем выразить, что fi находится в Di с:
ti → (1 ≤ mi ≤ 11 ∨ 18 ≤ mi ≤ 28)
¬ti → (29 ≤ mi ≤ 39 ∨ 46 ≤ mi ≤ 56)
, где ti указывает, является ли fi 2 по модулю 14 или нет, а mi представляет fi mod 14 .
Что касаетсяограничения, это будет зависеть от ti и tj . Их можно записать как
| 2 + 14mi - 8 - 14mj | > k
, когда (ti ∧ ¬tj) , и после некоторых манипуляций мы получим:
(ti ∧ ¬tj ) → ( mi−mj ≥ floor((k+6)/14 + 1 ∨ mi−mj ≤ ceil((-k-6)/14) - 1)
Мне удалось использоватьэто кодирование с помощью SolverFor ('QF_LIA'), и оно возвращает unsat , поскольку экземпляр невозможен.
Что мне не удалось сделать, так это кодировать его как Max-SMTпроблема.
Я попытался вместо этого использовать Оптимизировать и добавить мягкие ограничения с их весами, просто утверждая жесткие, но Z3 часами не дает мне ответа.
В статье говорится окаждое превращающееся взвешенное предложение
(Ci, wi) into (Ci ∨ pi)
, где pi - свежая пропозициональная переменная, а затем с использованием:
pi → (ki = wi) ¬pi → (ki = 0)
для весов. Но я еще не совсем понял.
Вопрос 1
Означает ли это, что
(ti ∧ ¬tj ) → ( mi−mj ≥ floor((k+6)/14 + 1 ∨ mi−mj ≤ ceil((-k-6)/14) - 1)
становится
((ti ∧ ¬tj ) → ( mi−mj ≥ floor((k+6)/14 + 1 ∨ mi−mj ≤ ceil((-k-6)/14) - 1) ∨ pi)
?
Вопрос 2
Как мне его кодировать, если я хочу минимизировать затраты и увидетьего ценность? Спасибо,
Редактировать
После публикации вопроса я потратил некоторое время на его взлом. Удалось заставить его работать на другом экземпляре (SUBCELAR6 / CELAR6-SUB0, который является небольшим под экземпляром экземпляра 6), но найденная стоимость (574) превышает оптимальную (159) найденную здесь
Репо можно найти здесь с набором данных , но основная часть:
import mongoengine as me
from models import Graph
from z3 import *
from math import ceil, floor
me.connect(db='tcc')
instance = next(Graph.objects(name='scen06'))
Vars = instance.var
Doms = instance.dom
Ctrs = instance.ctr
weights = {
1 : 1000,
2 : 100,
3 : 10,
4 : 1
}
s = Optimize()
for ctr in Ctrs:
ti = Bool('t_%d' % ctr.first_var)
tj = Bool('t_%d' % ctr.second_var)
mi = Int('m_%d' % ctr.first_var)
mj = Int('m_%d' % ctr.second_var)
k = ctr.deviation
# ti → (1 ≤ mi ≤ 11 ∨ 18 ≤ mi ≤ 28)
# ¬ti → (29 ≤ mi ≤ 39 ∨ 46 ≤ mi ≤ 56)
# Encoding the domain of Fi
s.add(Implies(ti, Or( And(1 <= mi, mi <= 11), And(18 <= mi, mi <= 28))))
s.add(Implies(Not(ti), Or( And(29 <= mi, mi <= 39), And(46 <= mi, mi <= 56))))
# Encoding the domain of Fj
s.add(Implies(tj , Or(And(1 <= mj, mj <= 11), And(18 <= mj, mj <= 28))))
s.add(Implies(Not(tj), Or(And(29 <= mj, mj <= 39), And(46 <= mj, mj <= 56))))
if ctr.operator == '=':
# (ti ∧ ¬tj )
s.add(Implies(And(ti,Not(tj)), Or(mi - mj == floor((k+6)/14) + 1, mi - mj == ceil((-k+6)/14) -1 )))
# (¬ti ∧ tj)
s.add(Implies(And(Not(ti),tj), Or(mi - mj == math.floor((k-6)/14) + 1, mi - mj == ceil((-k-6)/14) -1 )))
# (ti ∧ tj)
s.add(Implies(And(ti,tj), Or(mi - mj == math.floor(k/14) + 1, mi - mj == ceil(-k/14) -1 )))
# (¬ti ∧ ¬tj)
s.add(Implies(And(Not(ti),Not(tj)), Or(mi - mj == math.floor(k/14) + 1, mi - mj == ceil(-k/14) -1 )))
# encoding the soft constraints
if ctr.operator == '>':
weight = costs[ctr.weight]
# (ti ∧ ¬tj)
s.add_soft(
Implies(And(ti, Not(tj)), Or( mi - mj >= floor((k+6)/14) + 1, mi - mj <= ceil((-k+6)/14) -1 )),
weight
)
# (¬ti ∧ tj)
s.add_soft(
Implies( And(Not(ti), tj), Or( mi - mj >= floor((k-6)/14) + 1, mi - mj <= ceil((-k-6)/14) - 1 )),
weight
)
# (ti ∧ tj)
s.add_soft(
Implies(And(ti,tj) , Or( mi - mj >= floor(k/14) + 1 , mi - mj <= ceil(-k/14) -1 )),
weight
)
# (¬ti ∧ ¬tj)
s.add_soft(
Implies(And(Not(ti), Not(tj)), Or(mi - mj >= floor(k/14) + 1, mi - mj <= ceil(-k/14) -1 ))
, weight
)
print(s.check())
m = s.model()
print([ m.evaluate(o) for o in s.objectives() ])