Esempio n. 1
0
def get_bdd_for_aig_lit(lit):
    """ Convert AIGER lit into BDD.
    param lit: 'signed' value of gate
    returns: BDD representation of the input literal
    """
    # query cache
    if lit in lit_to_bdd:
        return lit_to_bdd[lit]
    # get stripped lit
    stripped_lit = aig.strip_lit(lit)
    if stripped_lit == error_fake_latch.lit:
        (intput, latch, and_gate) = (None, error_fake_latch, None)
    else:
        (intput, latch, and_gate) = aig.get_lit_type(stripped_lit)
    # is it an input, latch, gate or constant
    if intput or latch:
        result = bdd.BDD(stripped_lit)
    elif and_gate:
        result = (get_bdd_for_aig_lit(and_gate.rhs0)
                  & get_bdd_for_aig_lit(and_gate.rhs1))
    else:  # 0 literal, 1 literal and errors
        result = bdd.false()
    # cache result
    lit_to_bdd[stripped_lit] = result
    bdd_to_lit[result] = stripped_lit
    # check for negation
    if aig.lit_is_negated(lit):
        result = ~result
        lit_to_bdd[lit] = result
        bdd_to_lit[result] = lit
    return result
Esempio n. 2
0
def get_bdd_for_aig_lit(lit):
    """ Convert AIGER lit into BDD.
    param lit: 'signed' value of gate
    returns: BDD representation of the input literal
    """
    # query cache
    if lit in lit_to_bdd:
        return lit_to_bdd[lit]
    # get stripped lit
    stripped_lit = aig.strip_lit(lit)
    if stripped_lit == error_fake_latch.lit:
        (intput, latch, and_gate) = (None, error_fake_latch, None)
    else:
        (intput, latch, and_gate) = aig.get_lit_type(stripped_lit)
    # is it an input, latch, gate or constant
    if intput or latch:
        result = bdd.BDD(stripped_lit)
    elif and_gate:
        result = (get_bdd_for_aig_lit(and_gate.rhs0) &
                  get_bdd_for_aig_lit(and_gate.rhs1))
    else:  # 0 literal, 1 literal and errors
        result = bdd.false()
    # cache result
    lit_to_bdd[stripped_lit] = result
    bdd_to_lit[result] = stripped_lit
    # check for negation
    if aig.lit_is_negated(lit):
        result = ~result
        lit_to_bdd[lit] = result
        bdd_to_lit[result] = lit
    return result
Esempio n. 3
0
def synthesize():
    if use_trans:
        log.register_sum("trans_time",
                         "Time spent building transition relation: ")
        log.start_clock()
        compose_transition_bdd()
        log.stop_clock("trans_time")
    init_state_bdd = compose_init_state_bdd()
    error_bdd = bdd.BDD(error_fake_latch.lit)
    reach_over = []
    # use abstraction to minimize state space exploration
    if ini_reach:
        initial_abstraction()
        for j in range(ini_reach):
            preds.drop_latches()
            # add some latches
            make_vis = (aig.num_latches() + 1) // ini_reach_latches
            log.DBG_MSG("Making visible " + str(make_vis) + " latches")
            for i in range(make_vis):
                preds.loc_red()
            log.DBG_MSG("Computing reachable states over-app")
            abs_reach_region = fp(compose_abs_init_state_bdd(),
                                  fun=lambda x: x | post_bdd_abs(x))
            reach_over.append(gamma(abs_reach_region))
    # get the winning region for controller

    def min_pre(s):
        for r in reach_over:
            s = s.restrict(r)
        result = pre_env_bdd(s)
        for r in reach_over:
            result = result.restrict(r)
        return s | result

    log.DBG_MSG("Computing fixpoint of UPRE")
    win_region = ~fp(error_bdd,
                     fun=min_pre,
                     early_exit=lambda x: x & init_state_bdd != bdd.false())

    if win_region & init_state_bdd == bdd.false():
        log.LOG_MSG("The spec is unrealizable.")
        log.LOG_ACCUM()
        return (None, None)
    else:
        log.LOG_MSG("The spec is realizable.")
        log.LOG_ACCUM()
        return (win_region, reach_over)
Esempio n. 4
0
def synthesize():
    if use_trans:
        log.register_sum("trans_time",
                         "Time spent building transition relation: ")
        log.start_clock()
        compose_transition_bdd()
        log.stop_clock("trans_time")
    init_state_bdd = compose_init_state_bdd()
    error_bdd = bdd.BDD(error_fake_latch.lit)
    reach_over = []
    # use abstraction to minimize state space exploration
    if ini_reach:
        initial_abstraction()
        for j in range(ini_reach):
            preds.drop_latches()
            # add some latches
            make_vis = (aig.num_latches() + 1) // ini_reach_latches
            log.DBG_MSG("Making visible " + str(make_vis) + " latches")
            for i in range(make_vis):
                preds.loc_red()
            log.DBG_MSG("Computing reachable states over-app")
            abs_reach_region = fp(compose_abs_init_state_bdd(),
                                  fun=lambda x: x | post_bdd_abs(x))
            reach_over.append(gamma(abs_reach_region))
    # get the winning region for controller

    def min_pre(s):
        for r in reach_over:
            s = s.restrict(r)
        result = pre_env_bdd(s)
        for r in reach_over:
            result = result.restrict(r)
        return s | result

    log.DBG_MSG("Computing fixpoint of UPRE")
    win_region = ~fp(error_bdd,
                     fun=min_pre,
                     early_exit=lambda x: x & init_state_bdd != bdd.false())

    if win_region & init_state_bdd == bdd.false():
        log.LOG_MSG("The spec is unrealizable.")
        log.LOG_ACCUM()
        return (None, None)
    else:
        log.LOG_MSG("The spec is realizable.")
        log.LOG_ACCUM()
        return (win_region, reach_over)
Esempio n. 5
0
 def to_bdd(self):
     b = bdd.true()
     for c in self.clauses:
         nu_clause = bdd.false()
         for l in c:
             nu_var = bdd.BDD(abs(l))
             if l < 0:
                 nu_var = ~nu_var
             nu_clause |= nu_var
         b &= nu_clause
     return b
Esempio n. 6
0
 def to_bdd(self):
     b = bdd.true()
     for c in self.clauses:
         nu_clause = bdd.false()
         for l in c:
             nu_var = bdd.BDD(abs(l))
             if l < 0:
                 nu_var = ~nu_var
             nu_clause |= nu_var
         b &= nu_clause
     return b
Esempio n. 7
0
def test():
    cnf = aig.trans_rel_CNF()
    print cnf.to_string()
    for s in cnf.iter_solve():
        cnf2 = sat.CNF()
        cnf2.add_cube(s)
        if cnf2.to_bdd() & aig.trans_rel_bdd() == bdd.false():
            print "found an error!"
            aig.trans_rel_bdd().dump_dot()
            print str(s)
            print cnf2.to_string()
            exit()
        else:
            print str(s) + " works"
Esempio n. 8
0
def test():
    cnf = aig.trans_rel_CNF()
    print cnf.to_string()
    for s in cnf.iter_solve():
        cnf2 = sat.CNF()
        cnf2.add_cube(s)
        if cnf2.to_bdd() & aig.trans_rel_bdd() == bdd.false():
            print "found an error!"
            aig.trans_rel_bdd().dump_dot()
            print str(s)
            print cnf2.to_string()
            exit()
        else:
            print str(s) + " works"
Esempio n. 9
0
def abs_synthesis(compute_win_region=False):
    global use_abs

    # declare winner
    def declare_winner(controllable, conc_lose):
        log.LOG_MSG("Nr. of predicates: " + str(len(preds.abs_blocks)))
        log.LOG_ACCUM()
        if controllable:
            log.LOG_MSG("The spec is realizable.")
            if compute_win_region:
                # make sure we reached the fixpoint
                log.DBG_MSG("Get winning region")
                return (~fp(bdd.BDD(error_fake_latch.lit) | conc_lose,
                            fun=lambda x: x | pre_env_bdd(x)), [])
            else:
                return (~conc_lose, [])
            log.LOG_MSG("The spec is unrealizable.")
            return (None, [])

    # make sure that we have something to abstract
    if aig.num_latches() == 0:
        log.WRN_MSG("No latches in spec. Defaulting to regular synthesis.")
        use_abs = False
        return synthesize()
    # update loss steps
    local_loss_steps = (aig.num_latches() + 1) // loss_steps
    log.DBG_MSG("Loss steps = " + str(local_loss_steps))
    # registered quants
    steps = 0
    log.register_sum("ref_cnt", "Nr. of refinements: ")
    log.register_sum("abs_time", "Time spent abstracting: ")
    log.register_sum("uabs_time", "Time spent computing under-app of fp: ")
    log.register_sum("oabs_time", "Time spent exhausting info of over-app: ")
    log.register_average("unsafe_bdd_size",
                         "Average unsafe iterate bdd size: ")
    # create the abstract game
    initial_abstraction()
    error_bdd = alpha_under(bdd.BDD(error_fake_latch.lit))
    # add some latches
    if ini_latch:
        make_vis = (aig.num_latches() + 1) // ini_latch
        log.DBG_MSG("Making visible " + str(make_vis) + " latches")
        for i in range(make_vis):
            preds.loc_red()
    # first over-approx of the reachable region
    reachable_bdd = bdd.true()

    # The REAL algo
    while True:
        log.start_clock()
        if use_trans:
            transition_bdd = compose_abs_transition_bdd()
            log.BDD_DMP(transition_bdd, "transition relation")
        init_state_bdd = compose_abs_init_state_bdd()
        log.BDD_DMP(init_state_bdd, "initial state set")
        log.BDD_DMP(error_bdd, "unsafe state set")
        log.stop_clock("abs_time")

        # STEP 1: check if under-approx is losing
        log.DBG_MSG("Computing over approx of FP")
        log.start_clock()
        under_fp = fp(error_bdd,
                      fun=lambda x: (reachable_bdd &
                                     (x | pre_env_bdd_uabs(x))))
        log.stop_clock("uabs_time")
        if (init_state_bdd & under_fp) != bdd.false():
            return declare_winner(False)

        # STEP 2: exhaust information from the abstract game, i.e.
        # update the reachability information we have
        log.start_clock()
        prev_reach = bdd.false()
        reach = reachable_bdd
        while prev_reach != reach:
            prev_reach = reach
            # STEP 2.1: check if the over-approx is winning
            log.DBG_MSG("Computing over approx of FP")
            over_fp = fp(under_fp,
                         fun=lambda x: (reach &
                                        (x | pre_env_bdd_abs(x))))
            if (over_fp & init_state_bdd) == bdd.false():
                log.DBG_MSG("FP of the over-approx losing region not initial")
                return declare_winner(True, gamma(under_fp))
            # if there is no early exit we compute a strategy for Env
            env_strats = pre_env_bdd_abs(over_fp, get_strat=True)
            log.DBG_MSG("Computing over approx of Reach")
            reach = fp(init_state_bdd,
                       fun=lambda x: (reach & (x | post_bdd_abs(x,
                                               env_strats))))
        log.stop_clock("oabs_time")

        # STEP 3: refine or declare controllable
        log.DBG_MSG("Concretizing the strategy of Env")
        conc_env_strats = gamma(env_strats)
        conc_reach = gamma(reach)
        conc_under_fp = gamma(under_fp)
        log.DBG_MSG("Taking one step of UPRE in the concrete game")
        conc_step = single_pre_env_bdd(conc_under_fp,
                                       env_strat=conc_env_strats)
        conc_step &= conc_reach
        if bdd.make_impl(conc_step, conc_under_fp) == bdd.true():
            log.DBG_MSG("The concrete step revealed we are at the FP")
            return declare_winner(True, conc_under_fp)
        else:
            # drop latches every number of steps
            reset = False
            if (steps != 0 and steps % local_loss_steps == 0):
                log.DBG_MSG("Dropping all visible latches!")
                reset = preds.drop_latches()
            # add new predicates and reset caches if necessary
            nu_losing_region = conc_step | conc_under_fp
            reset |= preds.add_fixed_pred("reach", conc_reach)
            reset |= preds.add_fixed_pred("unsafe", nu_losing_region)
            # find interesting set of latches
            log.DBG_MSG("Localization reduction step.")
            reset |= preds.loc_red(not_imply=nu_losing_region)
            log.DBG_MSG("# of predicates = " + str(len(preds.abs_blocks)))
            if reset:
                reset_caches()
            # update error bdd
            log.push_accumulated("unsafe_bdd_size",
                                 nu_losing_region.dag_size())
            error_bdd = alpha_under(nu_losing_region)
            # update reachable area
            reachable_bdd = alpha_over(conc_reach)
            steps += 1
            log.push_accumulated("ref_cnt", 1)
Esempio n. 10
0
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
Esempio n. 11
0
def abs_synthesis(compute_win_region=False):
    global use_abs

    # declare winner
    def declare_winner(controllable, conc_lose):
        log.LOG_MSG("Nr. of predicates: " + str(len(preds.abs_blocks)))
        log.LOG_ACCUM()
        if controllable:
            log.LOG_MSG("The spec is realizable.")
            if compute_win_region:
                # make sure we reached the fixpoint
                log.DBG_MSG("Get winning region")
                return (~fp(bdd.BDD(error_fake_latch.lit) | conc_lose,
                            fun=lambda x: x | pre_env_bdd(x)), [])
            else:
                return (~conc_lose, [])
            log.LOG_MSG("The spec is unrealizable.")
            return (None, [])

    # make sure that we have something to abstract
    if aig.num_latches() == 0:
        log.WRN_MSG("No latches in spec. Defaulting to regular synthesis.")
        use_abs = False
        return synthesize()
    # update loss steps
    local_loss_steps = (aig.num_latches() + 1) // loss_steps
    log.DBG_MSG("Loss steps = " + str(local_loss_steps))
    # registered quants
    steps = 0
    log.register_sum("ref_cnt", "Nr. of refinements: ")
    log.register_sum("abs_time", "Time spent abstracting: ")
    log.register_sum("uabs_time", "Time spent computing under-app of fp: ")
    log.register_sum("oabs_time", "Time spent exhausting info of over-app: ")
    log.register_average("unsafe_bdd_size",
                         "Average unsafe iterate bdd size: ")
    # create the abstract game
    initial_abstraction()
    error_bdd = alpha_under(bdd.BDD(error_fake_latch.lit))
    # add some latches
    if ini_latch:
        make_vis = (aig.num_latches() + 1) // ini_latch
        log.DBG_MSG("Making visible " + str(make_vis) + " latches")
        for i in range(make_vis):
            preds.loc_red()
    # first over-approx of the reachable region
    reachable_bdd = bdd.true()

    # The REAL algo
    while True:
        log.start_clock()
        if use_trans:
            transition_bdd = compose_abs_transition_bdd()
            log.BDD_DMP(transition_bdd, "transition relation")
        init_state_bdd = compose_abs_init_state_bdd()
        log.BDD_DMP(init_state_bdd, "initial state set")
        log.BDD_DMP(error_bdd, "unsafe state set")
        log.stop_clock("abs_time")

        # STEP 1: check if under-approx is losing
        log.DBG_MSG("Computing over approx of FP")
        log.start_clock()
        under_fp = fp(error_bdd,
                      fun=lambda x:
                      (reachable_bdd & (x | pre_env_bdd_uabs(x))))
        log.stop_clock("uabs_time")
        if (init_state_bdd & under_fp) != bdd.false():
            return declare_winner(False)

        # STEP 2: exhaust information from the abstract game, i.e.
        # update the reachability information we have
        log.start_clock()
        prev_reach = bdd.false()
        reach = reachable_bdd
        while prev_reach != reach:
            prev_reach = reach
            # STEP 2.1: check if the over-approx is winning
            log.DBG_MSG("Computing over approx of FP")
            over_fp = fp(under_fp,
                         fun=lambda x: (reach & (x | pre_env_bdd_abs(x))))
            if (over_fp & init_state_bdd) == bdd.false():
                log.DBG_MSG("FP of the over-approx losing region not initial")
                return declare_winner(True, gamma(under_fp))
            # if there is no early exit we compute a strategy for Env
            env_strats = pre_env_bdd_abs(over_fp, get_strat=True)
            log.DBG_MSG("Computing over approx of Reach")
            reach = fp(init_state_bdd,
                       fun=lambda x:
                       (reach & (x | post_bdd_abs(x, env_strats))))
        log.stop_clock("oabs_time")

        # STEP 3: refine or declare controllable
        log.DBG_MSG("Concretizing the strategy of Env")
        conc_env_strats = gamma(env_strats)
        conc_reach = gamma(reach)
        conc_under_fp = gamma(under_fp)
        log.DBG_MSG("Taking one step of UPRE in the concrete game")
        conc_step = single_pre_env_bdd(conc_under_fp,
                                       env_strat=conc_env_strats)
        conc_step &= conc_reach
        if bdd.make_impl(conc_step, conc_under_fp) == bdd.true():
            log.DBG_MSG("The concrete step revealed we are at the FP")
            return declare_winner(True, conc_under_fp)
        else:
            # drop latches every number of steps
            reset = False
            if (steps != 0 and steps % local_loss_steps == 0):
                log.DBG_MSG("Dropping all visible latches!")
                reset = preds.drop_latches()
            # add new predicates and reset caches if necessary
            nu_losing_region = conc_step | conc_under_fp
            reset |= preds.add_fixed_pred("reach", conc_reach)
            reset |= preds.add_fixed_pred("unsafe", nu_losing_region)
            # find interesting set of latches
            log.DBG_MSG("Localization reduction step.")
            reset |= preds.loc_red(not_imply=nu_losing_region)
            log.DBG_MSG("# of predicates = " + str(len(preds.abs_blocks)))
            if reset:
                reset_caches()
            # update error bdd
            log.push_accumulated("unsafe_bdd_size",
                                 nu_losing_region.dag_size())
            error_bdd = alpha_under(nu_losing_region)
            # update reachable area
            reachable_bdd = alpha_over(conc_reach)
            steps += 1
            log.push_accumulated("ref_cnt", 1)
Esempio n. 12
0
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