def bmc(s: Solver) -> None:
    safety = syntax.And(*get_safety())

    n = utils.args.depth

    utils.logger.always_print(
        'bmc checking the following property up to depth %d' % n)
    utils.logger.always_print('  ' + str(safety))

    if not utils.args.relax:

        def bmc_normal(bound: int) -> Optional[Trace]:
            return logic.check_bmc(s, safety, bound)

        bmcer = bmc_normal
    else:

        def bmc_relaxed(bound: int) -> Optional[Trace]:
            return relaxed_traces.check_relaxed_bmc(safety, bound)

        bmcer = bmc_relaxed

    for k in range(0, n + 1):
        if (m := bmcer(k)) is not None:
            if utils.args.print_counterexample:
                print('found violation')
                print(str(m))
            break
    def as_onestate_formula(self, index: Optional[int] = None) -> Expr:
        # TODO: move to class State, this shouldn't be here
        assert self.num_states == 1 or index is not None, \
            'to generate a onestate formula from a multi-state model, ' + \
            'you must specify which state you want'
        assert index is None or (0 <= index and index < self.num_states)

        if index is None:
            index = 0

        if index not in self.onestate_formula_cache:
            prog = syntax.the_program

            mut_rel_interps = self.rel_interps[index]
            mut_const_interps = self.const_interps[index]
            mut_func_interps = self.func_interps[index]

            vs: List[syntax.SortedVar] = []
            ineqs: Dict[SortDecl, List[Expr]] = {}
            rels: Dict[RelationDecl, List[Expr]] = {}
            consts: Dict[ConstantDecl, Expr] = {}
            funcs: Dict[FunctionDecl, List[Expr]] = {}
            for sort in self.univs:
                vs.extend(syntax.SortedVar(v, syntax.UninterpretedSort(sort.name))
                          for v in self.univs[sort])
                u = [syntax.Id(v) for v in self.univs[sort]]
                ineqs[sort] = [syntax.Neq(a, b) for a, b in combinations(u, 2)]
            for R, l in chain(mut_rel_interps.items(), self.immut_rel_interps.items()):
                rels[R] = []
                for tup, ans in l.items():
                    e: Expr = (
                        syntax.AppExpr(R.name, tuple(syntax.Id(col) for col in tup))
                        if tup else syntax.Id(R.name)
                    )
                    rels[R].append(e if ans else syntax.Not(e))
            for C, c in chain(mut_const_interps.items(), self.immut_const_interps.items()):
                consts[C] = syntax.Eq(syntax.Id(C.name), syntax.Id(c))
            for F, fl in chain(mut_func_interps.items(), self.immut_func_interps.items()):
                funcs[F] = [
                    syntax.Eq(syntax.AppExpr(F.name, tuple(syntax.Id(col) for col in tup)),
                              syntax.Id(res))
                    for tup, res in fl.items()
                ]

            # get a fresh variable, avoiding names of universe elements in vs
            fresh = prog.scope.fresh('x', [v.name for v in vs])

            e = syntax.Exists(tuple(vs), syntax.And(
                *chain(*ineqs.values(), *rels.values(), consts.values(), *funcs.values(), (
                    syntax.Forall((syntax.SortedVar(fresh,
                                                    syntax.UninterpretedSort(sort.name)),),
                                  syntax.Or(*(syntax.Eq(syntax.Id(fresh), syntax.Id(v))
                                              for v in self.univs[sort])))
                    for sort in self.univs
                ))))
            assert prog.scope is not None
            with prog.scope.n_states(1):
                typechecker.typecheck_expr(prog.scope, e, None)
            self.onestate_formula_cache[index] = e
        return self.onestate_formula_cache[index]
def assert_any_transition(s: Solver,
                          t: Z3Translator,
                          state_index: int,
                          allow_stutter: bool = False) -> None:
    prog = syntax.the_program
    uid = str(state_index)

    tids = []
    for transition in prog.transitions():
        tid = z3.Bool(get_transition_indicator(uid, transition.name))
        tids.append(tid)
        s.add(
            z3.Implies(
                tid,
                t.translate_expr(
                    New(transition.as_twostate_formula(prog.scope),
                        state_index))))

    if allow_stutter:
        tid = z3.Bool(get_transition_indicator(uid, '$stutter'))
        tids.append(tid)
        frame = syntax.And(*DefinitionDecl._frame(prog.scope, mods=()))
        s.add(z3.Implies(tid, t.translate_expr(New(frame, state_index))))

    s.add(z3.Or(*tids))
Exemple #4
0
def relaxed_program(prog: syntax.Program) -> syntax.Program:
    new_decls: List[syntax.Decl] = [d for d in prog.sorts()]

    actives: Dict[syntax.SortDecl, syntax.RelationDecl] = {}
    for sort in prog.sorts():
        name = prog.scope.fresh('active_' + sort.name)
        r = syntax.RelationDecl(name, arity=[syntax.UninterpretedSort(sort.name)],
                                mutable=True, derived=None, annotations=[])
        actives[sort] = r
        new_decls.append(r)

    # active relations initial conditions: always true
    for sort in prog.sorts():
        name = prog.scope.fresh(sort.name[0].upper())
        expr = syntax.Forall([syntax.SortedVar(name, None)],
                             syntax.Apply(actives[sort].name, [syntax.Id(name)]))
        new_decls.append(syntax.InitDecl(name=None, expr=expr))

    for d in prog.decls:
        if isinstance(d, syntax.SortDecl):
            pass  # already included above
        elif isinstance(d, syntax.RelationDecl):
            if d.derived_axiom is not None:
                expr = syntax.relativize_quantifiers(actives, d.derived_axiom)
                new_decls.append(syntax.RelationDecl(d.name, d.arity, d.mutable, expr,
                                                     d.annotations))
            else:
                new_decls.append(d)
        elif isinstance(d, syntax.ConstantDecl):
            new_decls.append(d)
        elif isinstance(d, syntax.FunctionDecl):
            new_decls.append(d)
        elif isinstance(d, syntax.AxiomDecl):
            new_decls.append(d)
        elif isinstance(d, syntax.InitDecl):
            new_decls.append(d)
        elif isinstance(d, syntax.DefinitionDecl):
            assert not isinstance(d.body, syntax.BlockStatement), \
                "relax does not support transitions written in imperative syntax"
            mods, expr = d.body
            expr = syntax.relativize_quantifiers(actives, expr)
            if d.is_public_transition:
                guard = syntax.relativization_guard_for_binder(actives, d.binder)
                expr = syntax.And(guard, expr)
            new_decls.append(syntax.DefinitionDecl(d.is_public_transition, d.num_states, d.name,
                                                   params=d.binder.vs, body=(mods, expr)))
        elif isinstance(d, syntax.InvariantDecl):
            expr = syntax.relativize_quantifiers(actives, d.expr)
            new_decls.append(syntax.InvariantDecl(d.name, expr=expr,
                                                  is_safety=d.is_safety, is_sketch=d.is_sketch))
        else:
            assert False, d

    new_decls.append(relaxation_action_def(prog, actives=actives, fresh=True))

    res = syntax.Program(new_decls)
    res.resolve()  # #sorrynotsorry
    return res
Exemple #5
0
def verify_inductive_invariant(s: Solver, inv: List[Expr]) -> None:
    prog = syntax.the_program
    inits = [init.expr for init in prog.inits()]
    safeties = [inv.expr for inv in prog.invs() if inv.is_safety]

    assert logic.check_implication(s, inits, inv) is None
    assert logic.check_implication(s, inv, safeties) is None
    assert logic.check_two_state_implication_all_transitions(
        s, inv, syntax.And(*inv), minimize=False) is None
Exemple #6
0
def is_rel_blocking_relax(trns: Trace, idx: int,
                          derived_rel: Tuple[List[Tuple[syntax.SortedVar, str]], Expr]) -> bool:
    # TODO: probably can obtain the sort from the sortedvar when not using scapy
    free_vars, derived_relation_formula = derived_rel
    free_vars_active_clause = syntax.And(*(active_var(v.name, sort_name) for (v, sort_name) in free_vars))

    diffing_formula = syntax.Exists([v for (v, _) in free_vars],
                                    syntax.And(syntax.Old(syntax.And(free_vars_active_clause,
                                                                     derived_relation_formula)),
                                               syntax.And(free_vars_active_clause,
                                                          syntax.Not(derived_relation_formula))))

    with syntax.the_program.scope.two_state(twostate=True):  # TODO: what is this doing? probably misusing
        diffing_formula.resolve(syntax.the_program.scope, syntax.BoolSort)

    res = trns.eval_double_vocab(diffing_formula, idx)
    assert isinstance(res, bool)
    return cast(bool, res)
Exemple #7
0
def is_rel_blocking_relax_step(
        trns: Trace, idx: int,
        derived_rel: Tuple[List[Tuple[syntax.SortedVar, str]], Expr]
) -> bool:
    # TODO: probably can obtain the sort from the sortedvar when not using pickle
    free_vars, derived_relation_formula = derived_rel
    free_vars_active_clause = syntax.And(*(active_var(v.name, sort_name) for (v, sort_name) in free_vars))

    diffing_formula = syntax.Exists([v for (v, _) in free_vars],
                                    syntax.And(syntax.And(free_vars_active_clause,
                                                          derived_relation_formula),
                                               syntax.New(syntax.And(free_vars_active_clause,
                                                                     syntax.Not(derived_relation_formula)))))

    with syntax.the_program.scope.fresh_stack():
        with syntax.the_program.scope.n_states(2):
            diffing_formula.resolve(syntax.the_program.scope, syntax.BoolSort)

    res = trns.eval(diffing_formula, idx)
    assert isinstance(res, bool)
    return cast(bool, res)
Exemple #8
0
def itp_gen(s: Solver) -> None:
    k = 4

    prog = syntax.the_program
    safety = syntax.And(*(inv.expr for inv in prog.invs() if inv.is_safety))
    inits = [init.expr for init in prog.inits()]

    utils.logger.info("initial state: %s" % str(inits))
    utils.logger.info("proving safety property: %s" % safety)

    candidate = [safety]
    while True:
        cti = get_cti(s, syntax.And(*candidate))
        if cti is None:
            break

        pre_diag = cti[0]

        with logic.BoundedReachabilityCheck(s, syntax.the_program,
                                            k) as bmc_checker:
            core = bmc_checker.check_and_core(pre_diag)
        pre_diag.minimize_from_core(core)

        pre_diag.generalize(
            s, lambda diag: generalize_cex_omission_checker(s, diag, k))

        e = syntax.Not(pre_diag.to_ast())

        utils.logger.info('adding new clause to the invariant: %s' % str(e))
        candidate.append(e)

    res = logic.check_implication(s, inits, candidate)
    if res is not None:
        utils.logger.always_print(
            "Failure: candidate %s excludes initial states" %
            ' & '.join(str(clause) for clause in candidate))
    else:
        utils.logger.always_print("Success! Inductive invariant:")
        for clause in candidate:
            utils.logger.always_print(str(clause))
def relativize_decl(d: syntax.DefinitionDecl,
                    actives: Dict[syntax.SortDecl,
                                  syntax.RelationDecl], scope: syntax.Scope,
                    inline_relax_actives: bool) -> syntax.DefinitionDecl:
    mods, expr = d.mods, d.expr
    expr = syntax.relativize_quantifiers(actives, expr)
    if d.is_public_transition:
        guard = syntax.relativization_guard_for_binder(actives, d.binder)
        expr = syntax.And(guard, expr)

    if inline_relax_actives:
        new_mods, new_conjs = relax_actives_action_chunk(scope, actives)
        mods += new_mods
        expr = syntax.And(expr, *new_conjs)

    relativized_def = syntax.DefinitionDecl(d.is_public_transition,
                                            d.num_states,
                                            d.name,
                                            params=d.binder.vs,
                                            mods=mods,
                                            expr=expr)
    return relativized_def
Exemple #10
0
def itp_gen(s: Solver) -> None:
    k = utils.args.forward_depth

    prog = syntax.the_program
    safety = syntax.And(*(inv.expr for inv in prog.invs() if inv.is_safety))
    inits = [init.expr for init in prog.inits()]

    utils.logger.info("initial state: %s" % str(inits))
    utils.logger.info("proving safety property: %s" % safety)

    candidate = [safety]

    while True:
        cti = get_cti(s, syntax.And(*candidate))
        if cti is None:
            break

        pre_diag = cti[0]

        pre_diag.generalize(s,
                            lambda diag: bmc_upto_bound(
                                s, syntax.Not(diag.to_ast()), k) is None,
                            order=utils.args.generalization_order)

        e = syntax.Not(pre_diag.to_ast())

        utils.logger.info('adding new clause to the invariant: %s' % str(e))
        candidate.append(e)

    if logic.check_implication(s, inits, candidate) is not None:
        utils.logger.always_print(
            "Failure: candidate %s excludes initial states" %
            ' & '.join(str(clause) for clause in candidate))
    else:
        utils.logger.always_print("Success! Inductive invariant:")
        for clause in candidate:
            utils.logger.always_print(str(clause))
Exemple #11
0
def oneshot(s: Solver) -> None:
    prog = syntax.the_program
    safety = syntax.And(*(inv.expr for inv in prog.invs() if inv.is_safety))
    inits = [init.expr for init in prog.inits()]

    utils.logger.info("initial state: %s" % str(inits))
    utils.logger.info("proving safety property: %s" % safety)

    candidate = oneshot_compute_inv(s,
                                    utils.args.depth,
                                    inits,
                                    safety,
                                    minimize=utils.args.minimize_models)
    utils.logger.always_print("Got candidate:")
    for clause in candidate:
        utils.logger.always_print(str(clause))
    verify_inductive_invariant(s, candidate)
Exemple #12
0
def bmc(s: Solver) -> None:
    safety = syntax.And(*get_safety())

    n = utils.args.depth

    utils.logger.always_print('bmc checking the following property up to depth %d' % n)
    utils.logger.always_print('  ' + str(safety))

    for k in range(0, n + 1):
        m = logic.check_bmc(s, safety, k)
        if m is not None:
            if utils.args.print_counterexample:
                print('found violation')
                print(str(m))
            break
    else:
        print('no violation found.')
Exemple #13
0
def diagram_trace_to_explicitly_relaxed_trace(trace: RelaxedTrace, safety: Sequence[syntax.InvariantDecl]) -> None:
    relaxed_prog = relaxed_program(syntax.the_program)

    with syntax.prog_context(relaxed_prog):
        s = Solver()

        end_expr = syntax.Not(syntax.And(*(invd.expr for invd in safety)))
        with syntax.the_program.scope.n_states(1):
            end_expr.resolve(syntax.the_program.scope, syntax.BoolSort)
        trace_decl = diagram_trace_to_explicitly_relaxed_trace_decl(trace, end_expr)
        with syntax.the_program.scope.n_states(1):
            trace_decl.resolve(syntax.the_program.scope)

        print(trace_decl)

        res = bmc_trace(relaxed_prog, trace_decl, s, lambda slvr, ks: logic.check_solver(slvr, ks, minimize=True))
        print(res)
        assert False
Exemple #14
0
    def find_something_to_block(self) -> Optional[BackwardReachableState]:
        utils.logger.info('looking for something to block')

        while True:
            # for bstate in self.backwards_reachable_states:
            #     utils.logger.info(f'#{bstate.id} valid_up_to={bstate.known_absent_until_frame} '
            #                       f'steps_to_bad={bstate.num_steps_to_bad}')

            bstate_min = min(self.backwards_reachable_states,
                             key=lambda b: (b.known_absent_until_frame, b.num_steps_to_bad),
                             default=None)

            if bstate_min is None or (min_frame_no := bstate_min.known_absent_until_frame) == len(self) - 1:
                break

            if isinstance(state := bstate_min.state_or_expr, State):
                eval_res = state.eval(syntax.And(*(self[min_frame_no + 1].summary())))
                assert isinstance(eval_res, bool)
                if eval_res:
                    return bstate_min
Exemple #15
0
def brat(s: Solver) -> None:
    k = utils.args.depth

    prog = syntax.the_program
    safety = syntax.And(*(inv.expr for inv in prog.invs() if inv.is_safety))
    inits = [init.expr for init in prog.inits()]

    utils.logger.info("initial state: %s" % str(inits))
    utils.logger.info("proving safety property: %s" % safety)

    current_frame = inits
    prev_frame: List[Expr] = [syntax.FalseExpr]

    bad_cache: Set[Diagram] = set()

    idx = 0
    while logic.check_implication(s, current_frame, prev_frame,
                                  minimize=False) is not None:
        idx += 1
        prev_frame = current_frame
        if not utils.args.decrease_depth:
            current_depth = k
        else:
            current_depth = k - idx + 1
            if current_depth <= 0:
                assert False, "exhaused bmc depth: becoming non-positive"

        current_frame = brat_next_frame(s, prev_frame, current_depth, inits,
                                        safety, bad_cache,
                                        utils.args.minimize_models)
        utils.logger.info("Frame: %d" % idx)
        for c in current_frame:
            utils.logger.info(str(c))

    utils.logger.always_print("Success! Inductive invariant:")
    for clause in current_frame:
        utils.logger.always_print(str(clause))
    verify_inductive_invariant(s, current_frame)
Exemple #16
0
    def to_ast(self) -> Expr:
        e = syntax.And(*(c for _, _, c in self.conjuncts()))
        vs = self.binder.vs

        return syntax.Exists(vs, e)
def load_relaxed_trace_from_updr_cex(prog: Program, s: Solver) -> logic.Trace:
    import xml.dom.minidom  # type: ignore
    collection = xml.dom.minidom.parse(
        "paxos_derived_trace.xml").documentElement

    components: List[syntax.TraceComponent] = []

    xml_decls = reversed(collection.childNodes)
    seen_first = False

    for elm in xml_decls:
        if isinstance(elm, xml.dom.minidom.Text):  # type: ignore
            continue
        if elm.tagName == 'state':
            diagram = parser.parse_expr(elm.childNodes[0].data)
            typechecker.typecheck_expr(prog.scope, diagram, syntax.BoolSort)
            assert isinstance(
                diagram, syntax.QuantifierExpr) and diagram.quant == 'EXISTS'
            active_clauses = [
                relaxed_traces.active_var(v.name, str(v.sort))
                for v in diagram.get_vs()
            ]

            if not seen_first:
                # restrict the domain to be subdomain of the diagram's existentials
                seen_first = True
                import itertools  # type: ignore
                for sort, vars in itertools.groupby(
                        diagram.get_vs(),
                        lambda v: v.sort):  # TODO; need to sort first
                    free_var = syntax.SortedVar(
                        syntax.the_program.scope.fresh("v_%s" % str(sort)),
                        None)

                    # TODO: diagram simplification omits them from the exists somewhere
                    consts = list(
                        filter(lambda c: c.sort == sort, prog.constants()))
                    els: Sequence[Union[syntax.SortedVar, syntax.ConstantDecl]]
                    els = list(vars)
                    els += consts
                    restrict_domain = syntax.Forall(
                        (free_var, ),
                        syntax.Or(*(syntax.Eq(syntax.Id(free_var.name),
                                              syntax.Id(v.name))
                                    for v in els)))
                    active_clauses += [restrict_domain]

            diagram_active = syntax.Exists(
                diagram.get_vs(), syntax.And(diagram.body, *active_clauses))
            typechecker.typecheck_expr(prog.scope, diagram_active,
                                       syntax.BoolSort)

            components.append(syntax.AssertDecl(expr=diagram_active))
        elif elm.tagName == 'action':
            action_name = elm.childNodes[0].data.split()[0]
            tcall = syntax.TransitionCalls(
                calls=[syntax.TransitionCall(target=action_name, args=None)])
            components.append(syntax.TraceTransitionDecl(transition=tcall))
        else:
            assert False, "unknown xml tagName"

    trace_decl = syntax.TraceDecl(components=components, sat=True)
    migrated_trace = bmc_trace(
        prog,
        trace_decl,
        s,
        lambda s, ks: logic.check_solver(s, ks, minimize=True),
        log=False)

    assert migrated_trace is not None
    import pickle
    pickle.dump(migrated_trace, open("migrated_trace.p", "wb"))
    return migrated_trace
def relaxation_action_def(prog: syntax.Program,
                          actives: Optional[Dict[syntax.SortDecl,
                                                 syntax.RelationDecl]] = None,
                          fresh: bool = True) -> syntax.DefinitionDecl:
    decrease_name = (prog.scope.fresh('decrease_domain')
                     if fresh else 'decrease_domain')
    mods: Tuple[syntax.ModifiesClause, ...] = ()
    conjs: List[Expr] = []
    if actives is None:
        actives = active_rel_by_sort(prog)

    # a conjunct allowing each domain to decrease
    new_mods, new_conjs = relax_actives_action_chunk(prog.scope, actives)
    mods += new_mods
    conjs += new_conjs

    # constants are active
    for const in prog.constants():
        conjs.append(
            syntax.New(
                syntax.Apply(
                    actives[syntax.get_decl_from_sort(const.sort)].name,
                    (syntax.Id(const.name), ))))

    # functions map active to active
    for func in prog.functions():
        names: List[str] = []
        func_conjs = []
        for arg_sort in func.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            func_conjs.append(
                syntax.New(
                    syntax.Apply(actives[arg_sort_decl].name,
                                 (syntax.Id(name), ))))
        ap_func = syntax.Apply(func.name,
                               tuple(syntax.Id(name) for name in names))
        name = prog.scope.fresh('y', also_avoid=names)
        active_func = syntax.Let(
            syntax.SortedVar(name, func.sort), ap_func,
            syntax.New(
                syntax.Apply(
                    actives[syntax.get_decl_from_sort(func.sort)].name,
                    (syntax.Id(name), ))))
        conjs.append(
            syntax.Forall(
                tuple(syntax.SortedVar(name, None) for name in names),
                syntax.Implies(syntax.And(*func_conjs), active_func)))

    # (relativized) axioms hold after relaxation
    for axiom in prog.axioms():
        if not syntax.is_universal(axiom.expr):
            conjs.append(syntax.relativize_quantifiers(actives, axiom.expr))

    # derived relations have the same interpretation on the active domain
    for rel in prog.derived_relations():
        names = []
        rel_conjs = []
        for arg_sort in rel.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            rel_conjs.append(
                syntax.Apply(actives[arg_sort_decl].name, (syntax.Id(name), )))
        ap_rel = syntax.Apply(rel.name,
                              tuple(syntax.Id(name) for name in names))
        conjs.append(
            syntax.Forall(
                tuple(syntax.SortedVar(name, None) for name in names),
                syntax.Implies(syntax.And(*rel_conjs),
                               syntax.Iff(syntax.New(ap_rel), ap_rel))))

    return syntax.DefinitionDecl(is_public_transition=True,
                                 num_states=2,
                                 name=decrease_name,
                                 params=(),
                                 mods=mods,
                                 expr=syntax.And(*conjs))
Exemple #19
0
def derived_rels_candidates_from_trace(trns: Trace, more_traces: List[Trace],
                                       max_conj_size: int, max_free_vars: int) -> List[Tuple[List[syntax.SortedVar],Expr]]:
    first_relax_idx = first_relax_step_idx(trns)
    pre_relax_state = trns.as_state(first_relax_idx)
    post_relax_state = trns.as_state(first_relax_idx + 1)
    assert pre_relax_state.univs == post_relax_state.univs


    # relaxed elements
    relaxed_elements = []
    for sort, univ in pre_relax_state.univs.items():
        active_rel_name = 'active_' + sort.name         # TODO: de-duplicate
        pre_active_interp = dict_val_from_rel_name(active_rel_name, pre_relax_state.rel_interp)
        post_active_interp = dict_val_from_rel_name(active_rel_name, post_relax_state.rel_interp)
        pre_active_elements = [tup[0] for (tup, b) in pre_active_interp if b]
        post_active_elements = [tup[0] for (tup, b) in post_active_interp if b]
        assert set(post_active_elements).issubset(set(pre_active_elements))

        for relaxed_elem in utils.OrderedSet(pre_active_elements) - set(post_active_elements):
            relaxed_elements.append((sort, relaxed_elem))

    # pre-relaxation step facts concerning at least one relaxed element (other to be found by UPDR)
    relevant_facts: List[Union[RelationFact,FunctionFact,InequalityFact]] = []

    for rel, rintp in pre_relax_state.rel_interp.items():
        for rfact in rintp:
            (elms, polarity) = rfact
            relation_fact = RelationFact(rel, elms, polarity)
            if set(relation_fact.involved_elms()) & set(ename for (_, ename) in relaxed_elements):
                relevant_facts.append(relation_fact)

    for func, fintp in pre_relax_state.func_interp.items():
        for ffact in fintp:
            (els_params, els_res) = ffact
            function_fact = FunctionFact(func, els_params, els_res)
            if set(function_fact.involved_elms()) & set(ename for (_, ename) in relaxed_elements):
                relevant_facts.append(function_fact)

    for sort, elm in relaxed_elements: # other inequalities presumably handled by UPDR
        for other_elm in pre_relax_state.univs[sort]:
            if other_elm == elm:
                continue
            relevant_facts.append(InequalityFact(elm, other_elm))

    # facts blocking this specific relaxation step
    diff_conjunctions = []
    candidates_cache: Set[str] = set()
    for fact_lst in itertools.combinations(relevant_facts, max_conj_size):
        elements = utils.OrderedSet(itertools.chain.from_iterable(fact.involved_elms() for fact in fact_lst))
        relaxed_elements_relevant = [elm for (_, elm) in relaxed_elements if elm in elements]
        vars_from_elm = dict((elm, syntax.SortedVar(None, syntax.the_program.scope.fresh("v%d" % i), None))
                                for (i, elm) in enumerate(elements))
        parameter_elements = elements - set(relaxed_elements_relevant)
        if len(parameter_elements) > max_free_vars:
            continue

        conjuncts = [fact.as_expr(lambda elm: vars_from_elm[elm].name) for fact in fact_lst]

        # for elm, var in vars_from_elm.items():
        # TODO: make the two loops similar
        for elm in relaxed_elements_relevant:
            var = vars_from_elm[elm]
            sort = pre_relax_state.element_sort(elm)
            active_element_conj = syntax.Apply('active_%s' % sort.name, [syntax.Id(None, var.name)])
            conjuncts.append(active_element_conj)

        derived_relation_formula = syntax.Exists([vars_from_elm[elm]
                                                  for (_, elm) in relaxed_elements
                                                  if elm in vars_from_elm],
                                                 syntax.And(*conjuncts))

        if str(derived_relation_formula) in candidates_cache:
            continue
        candidates_cache.add(str(derived_relation_formula))

        if closing_qa_cycle(syntax.the_program, [pre_relax_state.element_sort(elm) for elm in parameter_elements],
                                                [pre_relax_state.element_sort(elm) for elm in relaxed_elements_relevant]):
            # adding the derived relation would close a quantifier alternation cycle, discard the candidate
            continue

        # if trns.eval_double_vocab(diffing_formula, first_relax_idx):
        if is_rel_blocking_relax(trns, first_relax_idx,
                                 ([(vars_from_elm[elm], pre_relax_state.element_sort(elm).name) for elm in parameter_elements],
                                  derived_relation_formula)):
            # if all(trs.eval_double_vocab(diffing_formula, first_relax_step_idx(trs)) for trs in more_traces):
                diff_conjunctions.append(([vars_from_elm[elm] for elm in parameter_elements],
                                           derived_relation_formula))

    return diff_conjunctions
Exemple #20
0
def relaxation_action_def(prog: syntax.Program,
                          actives: Optional[Dict[syntax.SortDecl, syntax.RelationDecl]]=None,
                          fresh: bool=True)  \
                            -> syntax.DefinitionDecl:
    decrease_name = (prog.scope.fresh('decrease_domain') if fresh else 'decrease_domain')
    mods = []
    conjs: List[Expr] = []
    if actives is None:
        actives = active_rel_by_sort(prog)

    # a conjunct allowing each domain to decrease
    for sort in prog.sorts():
        name = prog.scope.fresh(sort.name[0].upper())
        ap = syntax.Apply(actives[sort].name, [syntax.Id(None, name)])
        expr = syntax.Forall([syntax.SortedVar(None, name, None)],
                             syntax.Implies(ap, syntax.Old(ap)))
        conjs.append(expr)
        mods.append(syntax.ModifiesClause(None, actives[sort].name))

    # constants are active
    for const in prog.constants():
        conjs.append(syntax.Apply(actives[syntax.get_decl_from_sort(const.sort)].name,
                                  [syntax.Id(None, const.name)]))

    # functions map active to active
    for func in prog.functions():
        names: List[str] = []
        func_conjs = []
        for arg_sort in func.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            func_conjs.append(syntax.Apply(actives[arg_sort_decl].name, [syntax.Id(None, name)]))
        ap_func = syntax.Old(syntax.Apply(func.name, [syntax.Id(None, name) for name in names]))
        active_func = syntax.Apply(actives[syntax.get_decl_from_sort(func.sort)].name, [ap_func])
        conjs.append(syntax.Forall([syntax.SortedVar(None, name, None) for name in names],
                                   syntax.Implies(syntax.And(*func_conjs), active_func)))

    # (relativized) axioms hold after relaxation
    for axiom in prog.axioms():
        if not syntax.is_universal(axiom.expr):
            conjs.append(syntax.relativize_quantifiers(actives, axiom.expr))

    # derived relations have the same interpretation on the active domain
    for rel in prog.derived_relations():
        names = []
        rel_conjs = []
        for arg_sort in rel.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            rel_conjs.append(syntax.Apply(actives[arg_sort_decl].name, [syntax.Id(None, name)]))
        ap_rel = syntax.Apply(rel.name, [syntax.Id(None, name) for name in names])
        conjs.append(syntax.Forall([syntax.SortedVar(None, name, None) for name in names],
                                   syntax.Implies(syntax.And(*rel_conjs),
                                                  syntax.Iff(ap_rel, syntax.Old(ap_rel)))))

    return syntax.DefinitionDecl(None, public=True, twostate=True, name=decrease_name,
                                           params=[], body=(mods, syntax.And(*conjs)))