def extract_output_funcs(strategy, care_set=None): """ Calculate BDDs for output functions given non-deterministic winning strategy. """ if care_set is None: care_set = bdd.true() output_models = dict() all_outputs = get_controllable_inputs_bdds() for c in get_controllable_inputs_bdds(): others = set(set(all_outputs) - set([c])) if others: others_cube = bdd.get_cube(others) c_arena = strategy.exist_abstract(others_cube) else: c_arena = strategy # pairs (x,u) in which c can be true can_be_true = c_arena.cofactor(c) # pairs (x,u) in which c can be false can_be_false = c_arena.cofactor(~c) must_be_true = (~can_be_false) & can_be_true must_be_false = (~can_be_true) & can_be_false local_care_set = care_set & (must_be_true | must_be_false) # Restrict operation: # on care_set: must_be_true.restrict(care_set) <-> must_be_true c_model = min([must_be_true.safe_restrict(local_care_set), (~must_be_false).safe_restrict(local_care_set)], key=bdd.dag_size) output_models[c] = c_model log.DBG_MSG("Size of function for " + str(c.get_index()) + " = " + str(c_model.dag_size())) strategy &= bdd.make_eq(c, c_model) return output_models
def compose_abs_transition_bdd(): global cached_abs_transition, procd_blocks # check cache if cached_abs_transition is None: log.DBG_MSG("Rebuilding abstract transition relation") for b in preds.abs_blocks: procd_blocks[b] = False c = bdd.true() else: c = cached_abs_transition latches = [x.lit for x in iterate_latches_and_error()] latches_bdd = bdd.get_cube(get_all_latches_as_bdds()) latch_funs = [ get_bdd_for_aig_lit(x.next) for x in iterate_latches_and_error() ] for b in preds.abs_blocks: if b not in procd_blocks or not procd_blocks[b]: procd_blocks[b] = True temp = bdd.make_eq(bdd.BDD(get_primed_variable(b)), preds.block_to_bdd[b]) c &= temp.compose(latches, latch_funs) # cache c cached_abs_transition = c return c.and_abstract(compose_abs_eq_bdd(), latches_bdd)
def compose_abs_transition_bdd(): global cached_abs_transition, procd_blocks # check cache if cached_abs_transition is None: log.DBG_MSG("Rebuilding abstract transition relation") for b in preds.abs_blocks: procd_blocks[b] = False c = bdd.true() else: c = cached_abs_transition latches = [x.lit for x in iterate_latches_and_error()] latches_bdd = bdd.get_cube(get_all_latches_as_bdds()) latch_funs = [get_bdd_for_aig_lit(x.next) for x in iterate_latches_and_error()] for b in preds.abs_blocks: if b not in procd_blocks or not procd_blocks[b]: procd_blocks[b] = True temp = bdd.make_eq(bdd.BDD(get_primed_variable(b)), preds.block_to_bdd[b]) c &= temp.compose(latches, latch_funs) # cache c cached_abs_transition = c return c.and_abstract(compose_abs_eq_bdd(), latches_bdd)
def extract_output_funcs(strategy, care_set=None): """ Calculate BDDs for output functions given non-deterministic winning strategy. """ if care_set is None: care_set = bdd.true() output_models = dict() all_outputs = get_controllable_inputs_bdds() for c in get_controllable_inputs_bdds(): others = set(set(all_outputs) - set([c])) if others: others_cube = bdd.get_cube(others) c_arena = strategy.exist_abstract(others_cube) else: c_arena = strategy # pairs (x,u) in which c can be true can_be_true = c_arena.cofactor(c) # pairs (x,u) in which c can be false can_be_false = c_arena.cofactor(~c) must_be_true = (~can_be_false) & can_be_true must_be_false = (~can_be_true) & can_be_false local_care_set = care_set & (must_be_true | must_be_false) # Restrict operation: # on care_set: must_be_true.restrict(care_set) <-> must_be_true c_model = min([ must_be_true.safe_restrict(local_care_set), (~must_be_false).safe_restrict(local_care_set) ], key=bdd.dag_size) output_models[c] = c_model log.DBG_MSG("Size of function for " + str(c.get_index()) + " = " + str(c_model.dag_size())) strategy &= bdd.make_eq(c, c_model) return output_models
def compose_transition_bdd(): global cached_transition # check cache if cached_transition: return cached_transition b = bdd.true() for x in iterate_latches_and_error(): b &= bdd.make_eq(bdd.BDD(get_primed_variable(x.lit)), get_bdd_for_aig_lit(x.next)) cached_transition = b log.BDD_DMP(b, "Composed and cached the concrete transition relation") return b
def compose_abs_eq_bdd(): global cached_abs_eq, abs_eq_procd_blocks # check cache if cached_abs_eq is None: log.DBG_MSG("Rebuilding abs_eq") for b in preds.abs_blocks: abs_eq_procd_blocks[b] = False c = bdd.true() else: c = cached_abs_eq for b in preds.abs_blocks: if b not in procd_blocks or not procd_blocks[b]: c &= bdd.make_eq(bdd.BDD(b), preds.block_to_bdd[b]) # cache c cached_abs_eq = c return c
def over_post_bdd_abs(src_states_bdd, env_strat=None): # make sure the block_funs are current update_block_funs() # take the step forward and get rid of latches conc_src = gamma(src_states_bdd) if env_strat is not None: conc_strat = gamma(env_strat) else: conc_strat = bdd.true() # to do this, we use an over-simplified transition relation, EXu,Xc simple_trans = bdd.true() for b in preds.abs_blocks: trans_b = bdd.make_eq(bdd.BDD(b), block_funs[b]) simple_trans &= trans_b.exist_abstract( bdd.get_cube(get_controllable_inputs_bdds())) simple_trans &= conc_strat & conc_src return simple_trans.exist_abstract( bdd.get_cube(get_all_latches_as_bdds() + get_uncontrollable_inputs_bdds()))
def single_post_bdd(src_states_bdd, sys_strat=None): """ Over-approximated version of concrete post which can be done even without the transition relation """ strat = bdd.true() if sys_strat is not None: strat &= sys_strat # to do this, we use an over-simplified transition relation, EXu,Xc b = bdd.true() for x in iterate_latches_and_error(): temp = bdd.make_eq(bdd.BDD(get_primed_variable(x.lit)), get_bdd_for_aig_lit(x.next)) b &= temp.and_abstract(strat, bdd.get_cube(get_controllable_inputs_bdds())) if restrict_like_crazy: b = b.restrict(src_states_bdd) b &= src_states_bdd b = b.exist_abstract( bdd.get_cube(get_all_latches_as_bdds() + get_uncontrollable_inputs_bdds())) return unprime_latches_in_bdd(b)
def main(aiger_file_name, out_file): aig.parse_into_spec(aiger_file_name) log.DBG_MSG("AIG spec file parsed") log.LOG_MSG("Nr. of latches: " + str(aig.num_latches())) log.DBG_MSG("Latches: " + str([x.lit for x in iterate_latches_and_error()])) log.DBG_MSG("U. Inputs: " + str([x.lit for x in aig.iterate_uncontrollable_inputs()])) log.DBG_MSG("C. Inputs: " + str([x.lit for x in aig.iterate_controllable_inputs()])) # realizability and preliminary synthesis if use_abs: (win_region, reach_over) = abs_synthesis(out_file is not None) else: (win_region, reach_over) = synthesize() if out_file and win_region: log.LOG_MSG("Win region bdd node count = " + str(win_region.dag_size())) strategy = single_pre_sys_bdd(win_region, get_strat=True) log.LOG_MSG("Strategy bdd node count = " + str(strategy.dag_size())) func_by_var = extract_output_funcs(strategy, win_region) # attempt to minimize the winning region for r in reach_over: for (c_bdd, func_bdd) in func_by_var.items(): func_by_var[c_bdd] = func_bdd.safe_restrict(r) log.DBG_MSG("Min'd version size " + str(func_by_var[c_bdd].dag_size())) # attempt to minimize the winning region if min_win: bdd.disable_reorder() strategy = bdd.true() for (c_bdd, func_bdd) in func_by_var.items(): strategy &= bdd.make_eq(c_bdd, func_bdd) win_region = fp(compose_init_state_bdd(), fun=lambda x: x | post_bdd(x, strategy)) for (c_bdd, func_bdd) in func_by_var.items(): func_by_var[c_bdd] = func_bdd.safe_restrict(win_region) log.DBG_MSG("Min'd version size " + str(func_by_var[c_bdd].dag_size())) # model check? if model_check: strategy = bdd.true() for (c_bdd, func_bdd) in func_by_var.items(): strategy &= bdd.make_eq(c_bdd, func_bdd) assert (fp(bdd.BDD(error_fake_latch.lit), fun=lambda x: x | single_pre_bdd(x, strategy)) & compose_init_state_bdd()) == bdd.false() # print out the strategy total_dag = 0 for (c_bdd, func_bdd) in func_by_var.items(): total_dag += func_bdd.dag_size() model_to_aiger(c_bdd, func_bdd) log.LOG_MSG("Sum of func dag sizes = " + str(total_dag)) log.LOG_MSG("# of added gates = " + str(len(bdd_gate_cache))) aig.write_spec(out_file) return True elif win_region: return True else: return False