def attractor(bdd, g, i, f): k = 0 attr_old = f while True: # Code non-optimized # f_1 = g.tau & bdd.let(g.mapping_bis, attr_old) # f_1 = bdd.exist(g.bis_vars, f_1) f_1 = _bdd.and_exists(g.tau, bdd.let(g.mapping_bis, attr_old), g.bis_vars) # Code non-optimized # f_2 = g.tau & bdd.let(g.mapping_bis, (~attr_old)) # f_2 = ~(bdd.exist(g.bis_vars, f_2)) f_2 = ~_bdd.and_exists(g.tau, bdd.let(g.mapping_bis, ~attr_old), g.bis_vars) if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_new = attr_old | f_1 | f_2 if attr_new == attr_old: break attr_old = attr_new k = k + 1 return attr_old
def monotone_attractor(arena, s, priority, manager): """ Computes the monotone attractor of the target set, meaning the attractor without visiting bigger priorities than the one of the target set. :param arena: the arena in which we compute the attractor :type arena: Arena :param s: the set for which we compute the attractor :type s: dd.cudd.Function :param priority: the priority of vertices in s :type priority: int :param manager: the BDD manager :type manager: dd.cudd.BDD :return: the computed attractor :rtype: dd.cudd.Function """ player = priority % 2 # the player for which we compute the attractor old_attractor = manager.true new_attractor = manager.false # at first attractor only contains s vertices_smaller_priority = manager.false for prio, bdd in arena.priorities[0].items(): if prio <= priority: vertices_smaller_priority = vertices_smaller_priority | bdd # while a fixpoint is not reached while old_attractor != new_attractor: old_attractor = new_attractor # BDD representing the old attractor set, using prime variables old_attractor_prime = manager.let(arena.mapping_bis, old_attractor | s) # BDD representing vertices with at least one successor in the old attractor vertices_one_succ = bdd_func.and_exists(arena.edges, old_attractor_prime, arena.vars_bis) # BDD representing vertices with at least one successor outside the previous attractor vertices_all_succ = ~bdd_func.and_exists( arena.edges, ~old_attractor_prime, arena.vars_bis) # if we compute the attractor for player 0 if not player: player0_vertices_attractor = arena.player0_vertices & vertices_one_succ player1_vertices_attractor = arena.player1_vertices & vertices_all_succ else: player0_vertices_attractor = arena.player0_vertices & vertices_all_succ player1_vertices_attractor = arena.player1_vertices & vertices_one_succ # we impose that the computed predecessors have smaller or equal priority new_attractor = (old_attractor | player0_vertices_attractor | player1_vertices_attractor) & \ vertices_smaller_priority return new_attractor
def test_and_exists(): bdd = cudd.BDD() for var in ['x', 'y']: bdd.add_var(var) # (\E x: x /\ y) \equiv y x = bdd.add_expr('x') y = bdd.add_expr('y') qvars = ['x'] r = cudd.and_exists(x, y, qvars) assert r == y, (r, y) # (\E x: x /\ ~ x) \equiv FALSE not_x = bdd.apply('not', x) r = cudd.and_exists(x, not_x, qvars) assert r == bdd.false
def test_and_exists(): bdd = cudd.BDD() for var in ['x', 'y']: bdd.add_var(var) # \E x: x & y = y x = bdd.add_expr('x') y = bdd.add_expr('y') qvars = ['x'] r = cudd.and_exists(x, y, qvars, bdd) assert r == y, (r, y) # \E x: x & !x = 0 not_x = bdd.apply('not', x) r = cudd.and_exists(x, not_x, qvars, bdd) assert r == bdd.false
def p_safe_attractor_full(bdd, g, i, tau_e, u, avoid): # Non-optimized code # f_1 = (tau_e & bdd.let(g.mapping_bis, u)) & ~avoid # f_1 = bdd.exist(g.bis_vars + g.em_vars_bis, f_1) f_1 = _bdd.and_exists(tau_e, bdd.let(g.mapping_bis, u) & ~avoid, g.bis_vars + g.em_vars_bis) # Non-optimized code # f_2 = tau_e & bdd.let(g.mapping_bis, ~u) # f_2 = ~ bdd.exist(g.bis_vars + g.em_vars_bis, f_2) & ~avoid f_2 = ~_bdd.and_exists(tau_e, bdd.let(g.mapping_bis, ~u), g.bis_vars + g.em_vars_bis) & ~avoid if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_old = f_1 | f_2 while True: # Non-optimized code # f_1 = (tau_e & bdd.let(g.mapping_bis, attr_old)) & ~avoid # f_1 = bdd.exist(g.bis_vars + g.em_vars_bis, f_1) f_1 = _bdd.and_exists(tau_e, bdd.let(g.mapping_bis, attr_old) & ~avoid, g.bis_vars + g.em_vars_bis) # Non-optimized code # f_2 = tau_e & bdd.let(g.mapping_bis, ~(attr_old | u)) # f_2 = ~ bdd.exist(g.bis_vars + g.em_vars_bis, f_2) & ~avoid f_2 = ~_bdd.and_exists(tau_e, bdd.let(g.mapping_bis, ~(attr_old | u)), g.bis_vars + g.em_vars_bis) & ~avoid if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_new = attr_old | f_1 | f_2 if attr_new == attr_old: break attr_old = attr_new return attr_old
def test_and_exists(): bdd = cudd.BDD() for var in ['x', 'y']: bdd.add_var(var) # \E x: x & y = y x = bdd.add_expr('x') y = bdd.add_expr('y') qvars = ['x'] r = cudd.and_exists(x, y, qvars, bdd) assert r == y, (r, y) # \E x: x & !x = 0 not_x = bdd.apply('not', x) r = cudd.and_exists(x, not_x, qvars, bdd) assert r == bdd.false del x, not_x, y, r
def attractor_cudd(arena, s, player, manager): """ Computes the attractor of set s for player in the arena. This version uses cudd-specific functions. :param arena: the arena in which we compute the attractor :type arena: Arena :param s: the set for which we compute the attractor :type s: dd.cudd.Function :param player: the player for which we compute the attractor :type player: int :param manager: the BDD manager :type manager: dd.cudd.BDD :return: the computed attractor :rtype: dd.cudd.Function """ old_attractor = manager.false new_attractor = s # at first attractor only contains s # while a fixpoint is not reached while old_attractor != new_attractor: old_attractor = new_attractor # BDD representing the old attractor set, using prime variables old_attractor_prime = manager.let(arena.mapping_bis, old_attractor) # BDD representing vertices with at least one successor in the old attractor vertices_one_succ = bdd_func.and_exists(arena.edges, old_attractor_prime, arena.vars_bis) # BDD representing vertices with at least one successor outside the previous attractor vertices_all_succ = ~bdd_func.and_exists( arena.edges, ~old_attractor_prime, arena.vars_bis) # if we compute the attractor for player 0 if not player: # vertices in vertices_all_succ, which is a negation, that don't exist are ignored since they dont belong to # arena.player0_vertices player0_vertices_attractor = arena.player0_vertices & vertices_one_succ player1_vertices_attractor = arena.player1_vertices & vertices_all_succ else: player0_vertices_attractor = arena.player0_vertices & vertices_all_succ player1_vertices_attractor = arena.player1_vertices & vertices_one_succ new_attractor = old_attractor | player0_vertices_attractor | player1_vertices_attractor return new_attractor
def good_ep(bdd, g, i, tau_e): f_old = g.phi_0 | g.phi_1 while True: if i == 0: t = f_old & ~bdd.var(g.m_vars[0]) else: t = f_old & bdd.var(g.m_vars[0]) attr_t = attractor_pos_ext(bdd, g, i, t, tau_e) f = f_old & attr_t # For a vertice (v,m) check that m = P(v) id_prio_m = bdd.false for curr_p in range(g.d + 1): curr_p_point = num_to_map(curr_p, g.m_vars) curr_p_bdd = bdd.cube(curr_p_point) id_prio_m = id_prio_m | (g.gamma[curr_p] & curr_p_bdd) # Non-optimized code # f = f & id_prio_m # f = bdd.exist(g.m_vars, f) f = _bdd.and_exists(f, id_prio_m, g.m_vars) if f == f_old: break f_old = f return f
def good_ep_full(bdd, g, i, tau_e): f_old = g.phi_0 | g.phi_1 flat_m_vars_bis = [c_var for sublist in g.m_vars_bis for c_var in sublist] flat_m_vars = [c_var for sublist in g.m_vars for c_var in sublist] while True: t = f_old for prio_f_index in range(g.k): if i == 0: t = t & ~bdd.var(g.m_vars[prio_f_index][0]) else: t = t & bdd.var(g.m_vars[prio_f_index][0]) attr_t = attractor_pos_ext(bdd, g, i, t, tau_e, flat_m_vars_bis) f = f_old & attr_t # For a vertice (v,m_0, ..., m_k-1) check that m_l = P_l(v) id_prio_m = bdd.true for prio_f_index in range(g.k): curr_prio_m = bdd.false for curr_p in range(g.d[prio_f_index] + 1): curr_p_point = num_to_map(curr_p, g.m_vars[prio_f_index]) curr_p_bdd = bdd.cube(curr_p_point) curr_prio_m = curr_prio_m | (g.gamma[prio_f_index][curr_p] & curr_p_bdd) id_prio_m = id_prio_m & curr_prio_m # Non-optimized code # f = f & id_prio_m # f = bdd.exist(flat_m_vars, f) f = _bdd.and_exists(f, id_prio_m, flat_m_vars) if f == f_old: break f_old = f return f
def p_safe_attractor(bdd, g, i, u, avoid): # Code non-optimized # f_1 = (g.tau & bdd.let(g.mapping_bis, u)) & ~avoid # f_1 = bdd.exist(g.bis_vars, f_1) f_1 = _bdd.and_exists(g.tau, bdd.let(g.mapping_bis, u) & ~avoid, g.bis_vars) # Code non-optimized # f_2 = g.tau & bdd.let(g.mapping_bis, ~u) # f_2 = ~ bdd.exist(g.bis_vars, f_2) & ~ avoid f_2 = ~_bdd.and_exists(g.tau, bdd.let(g.mapping_bis, ~u), g.bis_vars) & ~avoid if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_old = f_1 | f_2 while True: # Code non-optimized # f_1 = g.tau & bdd.let(g.mapping_bis, attr_old) & ~avoid # f_1 = bdd.exist(g.bis_vars, f_1) f_1 = _bdd.and_exists(g.tau, bdd.let(g.mapping_bis, attr_old) & ~avoid, g.bis_vars) # Code non-optimized # f_2 = g.tau & bdd.let(g.mapping_bis, ~(attr_old | u)) # f_2 = ~bdd.exist(g.bis_vars, f_2) & ~avoid f_2 = ~_bdd.and_exists(g.tau, bdd.let(g.mapping_bis, ~(attr_old | u)), g.bis_vars) & ~avoid if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_new = attr_old | f_1 | f_2 if attr_new == attr_old: break attr_old = attr_new return attr_old
def attractor_pos(bdd, g, i, f): k = 1 # Code non-optimized # f_1 = (g.tau & bdd.let(g.mapping_bis, f)) # f_1 = bdd.exist(g.bis_vars, f_1) f_1 = bdd_func.and_exists(g.edges, bdd.let(g.mapping_bis, f), g.vars_bis) # Code non-optimized # f_2 = g.tau & bdd.let(g.mapping_bis, ~f) # f_2 = ~(bdd.exist(g.bis_vars, f_2)) f_2 = ~bdd_func.and_exists(g.edges, bdd.let(g.mapping_bis, ~f), g.vars_bis) if i == 0: f_1 = g.player0_vertices & f_1 f_2 = g.player1_vertices & f_2 else: f_1 = g.player1_vertices & f_1 f_2 = g.player0_vertices & f_2 attr_old = f_1 | f_2 while True: # Code non-optimized # f_1 = (g.tau & bdd.let(g.mapping_bis, attr_old)) # f_1 = (bdd.exist(g.bis_vars, f_1)) f_1 = bdd_func.and_exists(g.edges, bdd.let(g.mapping_bis, attr_old), g.vars_bis) # Code non-optimized # f_2 = g.tau & bdd.let(g.mapping_bis, ~(attr_old | f)) # f_2 = ~(bdd.exist(g.bis_vars, f_2)) f_2 = ~bdd_func.and_exists( g.edges, bdd.let(g.mapping_bis, ~(attr_old | f)), g.vars_bis) if i == 0: f_1 = g.player0_vertices & f_1 f_2 = g.player1_vertices & f_2 else: f_1 = g.player1_vertices & f_1 f_2 = g.player0_vertices & f_2 attr_new = attr_old | f_1 | f_2 if attr_new == attr_old: break attr_old = attr_new k = k + 1 return attr_old
def attractor_pos_ext(bdd, g, i, f, tau_e): # Non-optimized code # f_1 = (tau_e & bdd.let(g.mapping_bis, f)) # f_1 = bdd.exist(g.bis_vars + g.m_vars_bis, f_1) f_1 = _bdd.and_exists(tau_e, bdd.let(g.mapping_bis, f), g.bis_vars + g.m_vars_bis) # Non-optimized code # f_2 = tau_e & bdd.let(g.mapping_bis, ~f) # f_2 = ~(bdd.exist(g.bis_vars + g.m_vars_bis, f_2)) f_2 = ~_bdd.and_exists(tau_e, bdd.let(g.mapping_bis, ~f), g.bis_vars + g.m_vars_bis) if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_old = f_1 | f_2 while True: # Non-optimized code # f_1 = tau_e & bdd.let(g.mapping_bis, attr_old) # f_1 = bdd.exist(g.bis_vars + g.m_vars_bis, f_1) f_1 = _bdd.and_exists(tau_e, bdd.let(g.mapping_bis, attr_old), g.bis_vars + g.m_vars_bis) # Non-optimized code # f_2 = tau_e & bdd.let(g.mapping_bis, ~(attr_old | f)) # f_2 = ~(bdd.exist(g.bis_vars + g.m_vars_bis, f_2)) f_2 = ~_bdd.and_exists(tau_e, bdd.let(g.mapping_bis, ~(attr_old | f)), g.bis_vars + g.m_vars_bis) if i == 0: f_1 = g.phi_0 & f_1 f_2 = g.phi_1 & f_2 else: f_1 = g.phi_1 & f_1 f_2 = g.phi_0 & f_2 attr_new = attr_old | f_1 | f_2 if attr_new == attr_old: break attr_old = attr_new return attr_old