Эффективно создавайте структурированную диаграмму бинарных решений

Я пытаюсь создать BDD с определенной структурой. У меня есть одномерная последовательность логических переменных x_i, например x_1, x_2, x_3, x_4, x_5. Мое условие считается выполненным, если нет изолированных единиц или нулей (кроме, возможно, краев).

Я реализовал это с помощью pyeda следующим образом. Условие эквивалентно проверке последовательных троек ([x_1, x_2, x_3]; [x_2, x_3, x_4]; ...) и проверке того, что их значения истинности являются одним из [[1,1,1], [0,0,0], [1,1,0], [0,1,1], [1,0,0], [0,0,1]].

      from functools import reduce
from pyeda.inter import bddvars

def possible_3_grams(farr):
    farr = list(farr)
    poss = [[1,1,1], [0,0,0], [1,1,0], [0,1,1], [1,0,0], [0,0,1]]
    truths = [[farr[i] if p[i] else ~farr[i] for i in range(3)] for p in poss]
    return reduce(lambda x, y: x | y, [reduce(lambda x, y: x & y, t) for t in truths])

X = bddvars('x', k)
Xc = [X[i-1:i+2] for i in range(1,k-1)]
cont_constraints = [possible_3_grams(c) for c in Xc]
cont_constr = reduce(lambda x, y: x & y, cont_constraints)
print(cont_constr.to_dot())

Итоговая диаграмма выглядит так:

Это хорошо работает для коротких последовательностей, но последнее сокращение становится чрезвычайно медленным, когда длина превышает 25. Я бы хотел что-то, что работает для гораздо более длинных последовательностей.

Я подумал, не будет ли в данном случае более эффективным создание BDD напрямую, поскольку проблема имеет много структуры. Однако я не могу найти способ напрямую управлять BDD в pyeda.

Кто-нибудь знает, как я могу заставить это работать более эффективно?

1 ответ

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

      pip install dd

Например,

      from functools import reduce

from dd.autoref import BDD


def possible_3_grams(farr):
    farr = list(farr)
    poss = [[1, 1, 1], [0, 0, 0], [1, 1, 0], [0, 1, 1], [1, 0, 0], [0, 0, 1]]
    truths = [[farr[i] if p[i] else ~ farr[i] for i in range(3)] for p in poss]
    return reduce(lambda x, y: x | y, [reduce(lambda x, y: x & y, t) for t in truths])


def main():
    k = 100
    xvars = [f'x{i}' for i in range(k)]
    bdd = BDD()
    bdd.declare(*xvars)
    X = [bdd.add_expr(x) for x in xvars]
    Xc = [X[i-1:i+2] for i in range(1, k-1)]
    cont_constraints = [possible_3_grams(c) for c in Xc]
    cont_constr = reduce(lambda x, y: x & y, cont_constraints)
    print(cont_constr)
    bdd.dump('example.png', [cont_constr])

Вышеупомянутое использует чистую реализацию BDD на Python в модуле dd.autoref. В модуле доступна реализация Cython dd.cudd который взаимодействует с библиотекой CUDD в C.Эту реализацию можно использовать, заменив оператор импорта

      from dd.autoref import BDD

с заявлением

      from dd.cudd import BDD

Приведенный выше сценарий с использованием класса dd.autoref.BDD работает на k = 800(с комментариями к заявлению). Приведенный выше сценарий с использованием класса dd.cudd.BDD работает на k = 10000, при условии, что сначала отключено динамическое переупорядочение bdd.configure(reordering=False), и создает BDD с 39992 узлами (с bdd.dump заявление прокомментировано).

Диаграмма для k = 100 следующее:

Если также интересна минимизация двухуровневой логики, то она реализована в пакете omega, пример можно найти по адресу: https://github.com/tulip-control/omega/blob/master/examples/minimal_formula_from_bdd.py

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