def queens(n): solution = Robdd.true() # create the rule "there must be at least one queen at each line" for j in range(1, n + 1): line = Robdd.false() for i in range(1, n + 1): queen = Robdd.make_x(index_of(i, j)) line = synth(line, Bdd.OR, queen) solution = synth(solution, Bdd.AND, line) # create a list of "NOT" expressions not_expressions = {} for j in range(1, n + 1): for i in range(1, n + 1): not_expressions[(i, j)] = Robdd.make_not_x(index_of(i, j)) # create conditions for each position for j in range(1, n + 1): for i in range(1, n + 1): queen = queen_conditions(not_expressions, i, j, n) solution = synth(solution, Bdd.AND, queen) return solution
def remove_interval_up(original, s): r = Robdd.false() for i, b in enumerate(s): if b == '0': current_var = Robdd.make_x(i) r = synth(r, Bdd.OR, current_var) return synth(original, Bdd.AND, r)
def blah(): v = [ '1000000000000001', '1100000000000011', '1010000000000101', '1000000110000001', '1000100000010001', '1001000000001001', '1000010000100001', '1000001001000001', '1111000000001111', '1010010110100101', '1001100110011001', '1100110000110101', '1010101001010101', '1100001111000011', '1111111111111111' ] # # ''' # 1000010000100001 # 1000000110000001 # 1010000000000101 # 1010010110100101 # ''' # print v[2] solution = None for __v__ in v: if solution is None: solution = add_restriction(__v__) else: solution = synth(solution, Bdd.OR, add_restriction(__v__)) # solution = add_restriction(v[0]) # for i in range(len(v)): # if i in [0, 1, 13]: # continue # solution = synth(solution, Bdd.AND, add_negated(v[i])) # solution = remove_interval_down(solution, v[6]) # solution = remove_interval_down(solution, v[2]) # solution = remove_interval_down(solution, v[4]) # solution = remove_interval_down(solution, v[5]) # # solution = remove_interval_up(solution, v[1]) # solution = Robdd.make_x(0) # solution = synth(solution, Bdd.OR, Robdd.make_not_x(0)) # solution = synth(solution, Bdd.OR, Robdd.make_x(1)) solution = Robdd.false() solution = synth(solution, Bdd.OR, Robdd.make_not_x(0)) with open('/tmp/graph.dot', 'w') as fh: fh.write(solution.graphviz()) return solution
def add_restriction(s): r = Robdd.true() for i, b in enumerate(s): # if i == 0: # continue # if i >= 8 : # continue if b == '1': current_var = Robdd.make_x(i) else: current_var = Robdd.make_not_x(i) r = synth(r, Bdd.AND, current_var) return r
def add_negated(s): r = Robdd.false() for i, b in enumerate(s): # if i == 0: # continue # if i >= 8: # continue if b == '0': current_var = Robdd.make_x(i) else: current_var = Robdd.make_not_x(i) r = synth(r, Bdd.OR, current_var) return r
def queen_conditions(not_x, i, j, n) : queen = Robdd.make_x(index_of(i, j)) # creates the rule "none in the same column" a = Robdd.true() for y in range(1, n + 1) : if y == j : continue a_ = synth(queen, Bdd.IMPL, not_x[(i, y)]) a = synth(a, Bdd.AND, a_) # creates the rule "none in the same line" b = Robdd.true() for x in range(1, n + 1) : if x == i : continue b_ = synth(queen, Bdd.IMPL, not_x[(x, j)]) b = synth(b, Bdd.AND, b_) # creates the rule "none in the diagonals" c = Robdd.true() x = 1 while (i - x) > 0 and (j - x) > 0 : c_ = synth(queen, Bdd.IMPL, not_x[(i - x, j - x)]) c = synth(c, Bdd.AND, c_) x += 1 x = 1 while (i + x) <= n and (j + x) <= n : c_ = synth(queen, Bdd.IMPL, not_x[(i + x, j + x)]) c = synth(c, Bdd.AND, c_) x += 1 d = Robdd.true() x = 1 while (i - x) > 0 and (j + x) <= n : d_ = synth(queen, Bdd.IMPL, not_x[(i - x, j + x)]) d = synth(d, Bdd.AND, d_) x += 1 x = 1 while (i + x) <= n and (j - x) > 0 : d_ = synth(queen, Bdd.IMPL, not_x[(i + x, j - x)]) d = synth(d, Bdd.AND, d_) x += 1 return synth(synth(a, Bdd.AND, b), Bdd.AND, synth(c, Bdd.AND, d))
def queen_conditions(not_x, i, j, n): queen = Robdd.make_x(index_of(i, j)) # creates the rule "none in the same column" a = Robdd.true() for y in range(1, n + 1): if y == j: continue a_ = synth(queen, Bdd.IMPL, not_x[(i, y)]) a = synth(a, Bdd.AND, a_) # creates the rule "none in the same line" b = Robdd.true() for x in range(1, n + 1): if x == i: continue b_ = synth(queen, Bdd.IMPL, not_x[(x, j)]) b = synth(b, Bdd.AND, b_) # creates the rule "none in the diagonals" c = Robdd.true() x = 1 while (i - x) > 0 and (j - x) > 0: c_ = synth(queen, Bdd.IMPL, not_x[(i - x, j - x)]) c = synth(c, Bdd.AND, c_) x += 1 x = 1 while (i + x) <= n and (j + x) <= n: c_ = synth(queen, Bdd.IMPL, not_x[(i + x, j + x)]) c = synth(c, Bdd.AND, c_) x += 1 d = Robdd.true() x = 1 while (i - x) > 0 and (j + x) <= n: d_ = synth(queen, Bdd.IMPL, not_x[(i - x, j + x)]) d = synth(d, Bdd.AND, d_) x += 1 x = 1 while (i + x) <= n and (j - x) > 0: d_ = synth(queen, Bdd.IMPL, not_x[(i + x, j - x)]) d = synth(d, Bdd.AND, d_) x += 1 return synth(synth(a, Bdd.AND, b), Bdd.AND, synth(c, Bdd.AND, d))
def synthesize(self): if self.expression_a == None or not isinstance(self.expression_a, Robdd): raise "Expression A is not a Robdd object." if self.expression_b == None or not isinstance(self.expression_b, Robdd): raise "Expression B is not a Robdd object." if self.operator not in [Bdd.AND, Bdd.OR, Bdd.IMPL, Bdd.BIIMPL]: raise "Invalid operator." self.result = Robdd() self.result.root = self._synth(self.expression_a.root, self.expression_b.root) return self.result
def test_evaluate_should_return_true_for_x1(self): robdd = Robdd.false() v = robdd.make_x(0) robdd = synth(robdd, Bdd.OR, v) self.assertTrue(robdd.evaluate([1])) self.assertTrue(robdd.evaluate([1, 0])) self.assertTrue(robdd.evaluate([1, 1, 0, 1])) self.assertFalse(robdd.evaluate([0])) self.assertFalse(robdd.evaluate([0, 1])) self.assertFalse(robdd.evaluate([0, 1, 1, 1]))
def negate_bdd(bdd): neg_bdd = synthesize(bdd, Bdd.AND, Robdd.true()) for i in xrange(len(neg_bdd.items)): neg_bdd.items[i] = tuple( (neg_bdd.items[i][0], not neg_bdd.items[i][1] if neg_bdd.items[i][1] in (True, False) else neg_bdd.items[i][1], not neg_bdd.items[i][2] if neg_bdd.items[i][2] in (True, False) else neg_bdd.items[i][2])) # invert root, if root is a leaf if neg_bdd.root in (0, 1): neg_bdd.root ^= 1 return neg_bdd
def negate_bdd(bdd): neg_bdd = synthesize(bdd, Bdd.AND, Robdd.true()) for i in xrange(len(neg_bdd.items)): neg_bdd.items[i] = tuple((neg_bdd.items[i][0], not neg_bdd.items[i][1] if neg_bdd.items[i][1] in (True, False) else neg_bdd.items[i][ 1], not neg_bdd.items[i][2] if neg_bdd.items[i][2] in (True, False) else neg_bdd.items[i][ 2])) # invert root, if root is a leaf if neg_bdd.root in (0, 1): neg_bdd.root ^= 1 return neg_bdd
def get_minimal_element(robdd: Robdd, mapping_partition_to_boolean, mapping_boolean_to_partition, expected_value=1): bool_representation = robdd.get_random_solution(expected_value) if bool_representation is None: return None partition = Partition( mask=mapping_boolean_to_partition[tuple(bool_representation)].mask) while True: can_continue = False for partition_child in partition.subset_generator(): boolean_representation = mapping_partition_to_boolean[ partition_child.mask] if robdd.evaluate(boolean_representation) == expected_value: can_continue = True partition = partition_child if not can_continue: break return partition.mask
def test_get_minimal_element_should_work2(self): robdd = Robdd.false() a = (1, 1, 1, 1) pa = Partition(mask=(0, 0, 0)) b = (1, 1, 0, 0) pb = Partition(mask=(0, 0, 1)) c = (1, 0, 1, 0) pc = Partition(mask=(0, 1, 0)) d = (1, 0, 0, 1) pd = Partition(mask=(0, 1, 1)) e = (1, 0, 0, 0) pe = Partition(mask=(0, 1, 2)) robdd = synth(robdd, Bdd.OR, add_restriction(a)) robdd = synth(robdd, Bdd.OR, add_restriction(b)) robdd = synth(robdd, Bdd.OR, add_restriction(c)) robdd = synth(robdd, Bdd.OR, add_restriction(d)) mapping_partition_to_boolean = dict() mapping_partition_to_boolean[pa.mask] = a mapping_partition_to_boolean[pb.mask] = b mapping_partition_to_boolean[pc.mask] = c mapping_partition_to_boolean[pd.mask] = d mapping_partition_to_boolean[pe.mask] = e mapping_boolean_to_partition = dict() mapping_boolean_to_partition[a] = pa mapping_boolean_to_partition[b] = pb mapping_boolean_to_partition[c] = pc mapping_boolean_to_partition[d] = pd mapping_boolean_to_partition[e] = pe minimal_element = get_minimal_element(robdd, mapping_partition_to_boolean, mapping_boolean_to_partition) self.assertTrue(minimal_element == (0, 0, 1) or minimal_element == (0, 1, 0) or minimal_element == (0, 1, 1))
def main(): #Parse the command line arguments provided at run time. parser = argparse.ArgumentParser(description='ROBDD') parser.add_argument('-b', '--boolean_expr', dest='expr_1', metavar='B', type=str, nargs='?', help='Provide a boolean expression') parser.add_argument('-b2', '--boolean_expr2', dest='expr_2', metavar='B2', type=str, nargs='?', help='Provide a boolean expression') parser.add_argument( '-a', '--apply', dest='apply_expr', metavar='A', type=str, nargs='?', help='Provide the operation to apply (And, Or, Equal, Implies)') parser.add_argument('-r', '--restrict', dest='restrict_expr', metavar='R', type=str, nargs='?', help='Provide the restriction "var,val"') parser.add_argument('-s', '--sat', dest='sat', action='store_true', help='Return SAT on ROBDD') # Parse the input arguments args = parser.parse_args() if args.expr_1 is not None: expression1 = str(expr(args.expr_1)) print("Expression1: " + expression1) r1 = Robdd(find_large_var(expression1)) r1.build(expression1) r1.print_graph("r1") if args.expr_2 is not None: expression2 = str(expr(args.expr_2)) print("Expression2: " + expression2) r2 = Robdd(find_large_var(expression2)) r2.build(expression2) r2.print_graph("r2") if args.apply_expr is not None: r3 = Robdd_apply( max(find_large_var(expression1), find_large_var(expression2))) r3.apply(convert_apply(args.apply_expr), r1, r2) r3.print_graph("r3_apply") if args.restrict_expr is not None: r4 = Robdd_restrict(r1) r4.restrict(int(args.restrict_expr.split(',')[0]), int(args.restrict_expr.split(',')[1])) r4.print_graph('r4_restrict') if args.sat: r4 = Robdd_sat(r1) r4.print_SAT()
class Synthesis: def __init__(self): self.memo = {} self.operator = None self.expression_a = None self.expression_b = None self.result = None def synthesize(self): if self.expression_a == None or not isinstance(self.expression_a, Robdd): raise "Expression A is not a Robdd object." if self.expression_b == None or not isinstance(self.expression_b, Robdd): raise "Expression B is not a Robdd object." if self.operator not in [Bdd.AND, Bdd.OR, Bdd.IMPL, Bdd.BIIMPL]: raise "Invalid operator." self.result = Robdd() self.result.root = self._synth(self.expression_a.root, self.expression_b.root) return self.result def _synth(self, a_index, b_index): if (a_index, b_index) in self.memo: return self.memo[(a_index, b_index)] # print "_synth {}, {}".format(a_index, b_index) # print " A is leaf:", self._is_leaf(a_index) # print " B is leaf:", self._is_leaf(b_index) i_a, t_a, f_a = self.expression_a.items[a_index] i_b, t_b, f_b = self.expression_b.items[b_index] if self._is_leaf(a_index) and self._is_leaf(b_index): # print " operating leaves" result = self._operate(a_index, b_index) elif i_a == i_b: # print " operating nodes" result = self.result.insert(i_a, self._synth(t_a, t_b), self._synth(f_a, f_b)) elif i_a < i_b: # print " advancing A" result = self.result.insert(i_a, self._synth(t_a, b_index), self._synth(f_a, b_index)) # elif i_a > i_b: else: # print " advancing B" result = self.result.insert(i_b, self._synth(a_index, t_b), self._synth(a_index, f_b)) self.memo[(a_index, b_index)] = result return result def _operate(self, a_index, b_index): a = self._index_to_bool(a_index) b = self._index_to_bool(b_index) if self.operator == Bdd.AND: return a and b if self.operator == Bdd.OR: return a or b if self.operator == Bdd.IMPL: return False if (a and not b) else True if self.operator == Bdd.BIIMPL: return a == b raise "Unknown operator." def _is_leaf(self, index): return index == 0 or index == 1 def _index_to_bool(self, index): return index == 1
def test_get_minimal_element_should_return_none_if_empty(self): robdd = Robdd.false() self.assertIsNone(get_minimal_element(robdd, dict(), dict()))
def test_evaluate_should_always_return_false(self): robdd = Robdd.false() self.assertFalse(robdd.evaluate([0])) self.assertFalse(robdd.evaluate([1])) self.assertFalse(robdd.evaluate([0, 0])) self.assertFalse(robdd.evaluate([0, 1, 1, 0]))
def test_evaluate_should_always_return_true(self): robdd = Robdd.true() self.assertTrue(robdd.evaluate([0])) self.assertTrue(robdd.evaluate([1])) self.assertTrue(robdd.evaluate([0, 0])) self.assertTrue(robdd.evaluate([0, 1, 1, 0]))