Ограничение K-вне-N в Z3Py

Я использую привязки Python для программы доказательства теорем Z3 (Z3Py). У меня есть N логических переменных, x1, .., xN. Я хочу выразить ограничение, согласно которому ровно K из N из них должны быть истинными. Как я могу это сделать в Z3Py? Есть ли для этого встроенная поддержка? Я проверил онлайн-документацию, но в Z3Py docs не упоминается любой API для этого.

Я знаю, что для ограничений один из N я могу отдельно выразить, что по крайней мере одно истинно (assert Or (x1, .., xN)) и что самое большее одно истинно (assert Not (And (xi, xj )) для всех i, j). Я также знаю другие способы, чтобы вручную выразить 1-из-N и K-из-из- N ограничений. Однако у меня сложилось впечатление, что, когда решатель имеет встроенную поддержку этого ограничения, иногда он может быть более эффективным, чем выражение его вручную.


person D.W.    schedule 28.03.2017    source источник


Ответы (1)


Да, Z3Py имеет встроенную поддержку для этого. Для этого существует недокументированный API, который не упоминается в документации Z3Py: используйте PbEq. В частности, выражение

PbEq(((x1,1),(x2,1),..,(xN,1)),K)

будет истинным, если ровно K из N логических переменных установлено в истинное значение. Есть некоторые отчеты о том, что эта кодировка будет быстрее, чем наивные способы выражения ограничения вручную.

Чтобы выразить ограничение 1 из N, просто установите K = 1 и используйте PbEq. Чтобы выразить ограничение не более K из N, используйте PbLe. Чтобы выразить ограничение как минимум K из N, используйте PbGe.

Вы можете выразить это в Python так:

import z3

s = z3.Solver()
bvars = [z3.Bool("Var {0}".format(x)) for x in range(10)]
#Exactly 3 of the variables should be true
s.add( z3.PbEq([(x,1) for x in bvars], 3) )
s.check()
m = s.model()

s = z3.Solver()
bvars = [z3.Bool("Var {0}".format(x)) for x in range(10)]
#<=3 of the variables should be true
s.add( z3.PbLe([(x,1) for x in bvars], 3) )
s.check()
m = s.model()

s = z3.Solver()
bvars = [z3.Bool("Var {0}".format(x)) for x in range(10)]
#>=3 of the variables should be true
s.add( z3.PbGe([(x,1) for x in bvars], 3) )
s.check()
m = s.model()
person D.W.    schedule 28.03.2017
comment
Интересно. Есть ли способ получить доступ к PbEq через интерфейс smt-lib? (возможно, с помощью тактики или какой-то другой магии z3?) - person alias; 31.03.2017
comment
@LeventErkok, я не знаю. Хороший вопрос! Внутренний API C / C ++ - Z3_mk_pbeq (). - person D.W.; 31.03.2017
comment
Подали заявку здесь, чтобы узнать, смогут ли люди z3 найти способ: github.com/Z3Prover/ z3 / issues / 960 - person alias; 31.03.2017
comment
Синтаксис SMT-LIB: ((_ не более k) xyzuv), ((_ не менее k) xyzuv), ((_ pbge c1 c2 c3 c4 c5 k) xyzuv), ((_ pble c1 c2 c3 c4 c5 k) xyzuv), ((_ pbeq c1 c2 c3 c4 c5 k) xyzuv), Если вы используете только битовые векторы и ограничения PB, тогда установите логику на QF_FD (конечные области без кванторов). Затем он использует решатель SAT. - person Nikolaj Bjorner; 31.03.2017