Макс. список векторов логических значений с использованием z3 для решения проблемы SAT

Я работаю над проектом 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.

Я ожидаю функцию, которая возвращает ограничения, чтобы найти максимальное значение списка логических векторов, которые будут использоваться в решателе.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

У меня работает следующий вариант вашего кода:

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]

чего вы и ожидали.

Другие вопросы по теме

Как я могу получить текущее значение параметра локальной конфигурации postgresql?
Есть ли у движков JavaScript какие-то специальные оптимизации для классов?
Избегание оценки дорогостоящей функции в targetpenalty, которая уже была оценена по стоимости (мистический пакет оптимизации python)
Как мне организовать это многопоточное приложение, чтобы оно не зависало в "ожидании" блокировок?
Нужны входные данные для оптимизации большого размера Mysql - Таблица Innodb
Эффективно удалять максимальное количество двоичных элементов, сохраняя при этом суммы строк и столбцов выше определенного уровня
Как выполнить быстрый программный биннинг изображения на С++?
Самый быстрый способ привести диапазон [от, до] 64-битных целых чисел в псевдослучайный порядок с одинаковыми результатами на всех платформах?
Оптимизация небольших строк — как эффективно отслеживать строковый режим
Оптимизация Python и Gekko