Я работаю над проектом Sat, одна из моих подзадач - вычислить максимум списка векторов логических значений, каждый из которых является числом. Примером вектора является [False,True,True,False], он представляет число 2^2 + 2^1 = 6. В этом разрешении я не могу использовать данные Int z3, но я должен использовать только данные Bool z3. Чтобы решить эту проблему, я попытался использовать следующий код, но он не работает.
from z3 import *
def greater(vec1, vec2, name):
constraints = []
gt = [Bool(f"gt_{name}{i}") for i in range(len(vec1))]
constraints.append(
And(
[
Implies(Not(vec1[0]), Not(vec2[0])),
Implies(And(vec1[0], Not(vec2[0])), gt[0]),
Implies(Not(Xor(vec1[0], vec2[0])), Not(gt[0]))]
)
)
for i in range(1, len(vec1)):
constraints.append(
And(
Or(gt[i-1],
And(
[
Implies(Not(vec1[i]), Not(vec2[i])),
Implies(And(vec1[i], Not(vec2[i])), gt[i]),
Implies(Not(Xor(vec1[i], vec2[i])), Not(gt[i]))]
)
),
Implies(gt[i-1], gt[i])
)
)
return And(constraints)
def max_of_bin_int(values, max_values):
constraints = []
len_bits = len(values[0])
constraints.append(
And([max_values[0][j] == values[0][j] for j in range(len_bits)]),
)
for i in range(0, len(values)-1):
constraints.append(
If(greater(max_values[i], values[i+1], f"max{i}"),
And([max_values[i+1][j] == max_values[i][j] for j in range(len_bits)]),
And([max_values[i+1][j] == values[i+1][j] for j in range(len_bits)])
)
)
return And(constraints)
# Testing
values = [ [True,True,True,False],
[True,True,False,False],
[True,True,False,False]
]
s = Solver()
max_values = [[Bool(f"x_{i}_{j}") for j in range(len(values[0]))] for i in range(len(values)) ]
s.add(max_of_bin_int(values, max_values))
print(s.check())
m = s.model()
print([m.evaluate(max_values[-1][j]) for j in range(len(values[0]))] )
Результат, который возвращает функция, — [Истина, Истина, Ложь, Ложь], но он должен быть [Истина,Истина,Истина,Ложь]. Может ли кто-нибудь мне помочь?
Важно:
Я не могу использовать данные Int z3, только данные Bool.
Я ожидаю функцию, которая возвращает ограничения, чтобы найти максимальное значение списка логических векторов, которые будут использоваться в решателе.






У меня работает следующий вариант вашего кода:
from z3 import *
def greater(vec1, vec2):
"""
cf. https://en.wikipedia.org/wiki/Digital_comparator
"""
bits = len(vec1)
msb = bits-1
gt = And(vec1[msb], Not(vec2[msb]))
x = (vec1[msb] == vec2[msb])
for i in reversed(range(msb)):
gt = Or(gt, And(x, vec1[i], Not(vec2[i])))
x = And(x, (vec1[i] == vec2[i]))
return gt
def max_of_bin_int(values, max_values):
rBits = range(len(values[0]))
constraints = [max_values[0][j] == values[0][j] for j in rBits]
for i in range(1, len(values)):
gt = greater(max_values[i-1], values[i])
constraints.append(
And([max_values[i][j] == If(gt, max_values[i-1][j], values[i][j]) for j in rBits])
)
return And(constraints)
# Testing
values = [[True,True,True,False],
[True,True,False,False],
[True,True,True,True],
[True,True,False,False]
]
s = Solver()
rColumns = range(len(values[0]))
rRows = range(len(values))
max_values = [[Bool(f"x_{row}_{col}") for col in rColumns] for row in rRows]
s.add(max_of_bin_int(values, max_values))
print(s.check())
m = s.model()
print([m.evaluate(max_values[-1][col]) for col in rColumns] )
Я изменил логику векторного компаратора, вдохновленную Википедией.
Ваша функция greater не возвращает правильное условие для управления функцией If(). Он выполняет сравнение в неправильном порядке битов. Цифровой компаратор начинает со старшего бита (MSB) и спускается к младшему биту. Я использую reversed(range()), чтобы сделать заказ правильно.
Сначала некоторые предварительные сведения:
from z3 import *
from functools import *
s = Solver()
Сравнение двух логических векторов, интерпретируемых как числа без знака, равнозначно лексикографическому (то есть словарному) порядку. Итак, давайте сначала напишем предикат, который проходит по двум спискам одинаковой длины и определяет, является ли первый большим или равным второму:
def gte(xs, ys):
if not xs:
return BoolVal(True)
else:
return If(xs[0] == ys[0], gte(xs[1:], ys[1:]), xs[0])
Теперь, когда у нас есть метод, который сравнивает два битовых вектора, давайте напишем еще один, который возвращает больший из двух заданных векторов. Мы делаем это, объявляя переменную fresh, чтобы мы могли сохранить результат сравнения, гарантируя, что результат сравнения будет общим для целей эффективности:
def greater(xs, ys):
comp = FreshBool()
s.add(comp == gte(xs, ys))
return [If(comp, i, j) for i, j in zip(xs, ys)]
Собрав эти две части вместе, все, что нам нужно, — это уменьшить набор векторов, вернув наибольший элемент. Для этого воспользуемся функцией reduce из functools:
def max_vectors(vss):
return reduce(greater, vss)
И вот ваш тестовый код, адаптированный для работы с этими определениями:
values = [ [True, True, True, False]
, [True, True, False, False]
, [True, True, False, False]
]
res = [Bool(f"res_{i}") for i in range(len(values[0]))]
for r, i in zip(res, max_vectors(values)):
s.add(r == i)
print(s.check())
m = s.model()
print([m.evaluate(b, model_completion = True) for b in res])
Это печатает:
sat
[True, True, True, False]
чего вы и ожидали.