示例#1
0
def _encode_transitions_ucw(reach_func_desc: FuncDesc,
                            rank_func_desc: FuncDesc,
                            tau_desc: FuncDesc,
                            desc_by_output: Dict[Signal, FuncDesc],
                            inputs: List[Signal],
                            q: Node,
                            m: int,
                            i_o: Label,
                            state_to_final_scc: dict = None) -> List[str]:
    # syntax sugar
    def smt_r(smt_m: str, smt_q: str):
        return call_func(rank_func_desc, {
            ARG_MODEL_STATE: smt_m,
            ARG_A_STATE: smt_q
        })

    def smt_reach(smt_m: str, smt_q: str):
        return call_func(reach_func_desc, {
            ARG_MODEL_STATE: smt_m,
            ARG_A_STATE: smt_q
        })

    def smt_tau(smt_m: str, i_o: Label):
        tau_args = build_tau_args_dict(inputs, smt_m, i_o)
        return call_func(tau_desc, tau_args)

    #

    smt_m, smt_q = smt_name_m(m), smt_name_q(q)
    smt_m_next = smt_tau(smt_m, i_o)

    smt_pre = op_and(
        [smt_reach(smt_m, smt_q),
         smt_out(smt_m, i_o, inputs, desc_by_output)])

    smt_post_conjuncts = []
    for q_next, is_fin in q.transitions[i_o]:
        if is_final_sink(q_next):
            smt_post_conjuncts = [false()]
            break

        smt_q_next = smt_name_q(q_next)

        smt_post_conjuncts.append(smt_reach(smt_m_next, smt_q_next))

        greater_op = _get_greater_op_ucw(q, is_fin, q_next, state_to_final_scc)
        if greater_op is not None:
            smt_post_conjuncts.append(
                greater_op(smt_r(smt_m, smt_q), smt_r(smt_m_next, smt_q_next)))

    smt_post = op_and(smt_post_conjuncts)
    pre_implies_post = op_implies(smt_pre, smt_post)
    free_input_args = get_free_input_args(i_o, inputs)

    return [assertion(forall_bool(free_input_args, pre_implies_post))]
示例#2
0
            def _visit_prop(self, sig: Signal, number: Number) -> str:
                # TODO: run it
                # Encode into SMT proposition `DstFormulaProp`, i.e., smth. like
                #   (r&E(c), q_next)
                # It should become
                #   \exists c: reach(q_next, tau(t, r, ?c)) &
                #              rank(q,t)<>rank(q_next, tau(t, r, ?c))

                assert number == Number(
                    1), "program invariant: propositions are positive"
                dstFormProp = self.encoder.dstPropMgr.get_dst_form_prop(
                    sig.name)

                ext_label, q_next = dstFormProp.ext_label, dstFormProp.dst_state

                # build s_m_next, s_q_next
                tau_input_args_dict, free_input_args = build_inputs_values(
                    self.encoder.inputs, ext_label.fixed_inputs)
                tau_input_args_dict[ARG_MODEL_STATE] = smt_name_m(self.m)

                s_m_next = call_func(self.encoder.tau_desc,
                                     tau_input_args_dict)
                s_q_next = smt_name_q(q_next)

                # build reach_next
                reach_next_args = {
                    ARG_A_STATE: s_q_next,
                    ARG_MODEL_STATE: s_m_next
                }
                reach_next = call_func(self.encoder.reach_func_desc,
                                       reach_next_args)

                # build rank_cmp
                rank_args = {
                    ARG_A_STATE: smt_name_q(self.q),
                    ARG_MODEL_STATE: smt_name_m(self.m)
                }
                rank_next_args = reach_next_args
                rank = call_func(self.encoder.rank_func_desc, rank_args)
                rank_next = call_func(self.encoder.rank_func_desc,
                                      rank_next_args)
                rank_cmp_op = self.encoder._get_greater_op(q_next)
                rank_cmp = rank_cmp_op(rank,
                                       rank_next) if rank_cmp_op else true()

                # build `\exists[forall]: reach_next & rank_cmp`
                reach_and_rank_cmp = op_and([reach_next, rank_cmp])

                op = (forall_bool,
                      exists_bool)[ext_label.type_ == ExtLabel.EXISTS]

                return op(free_input_args, reach_and_rank_cmp)
示例#3
0
def _encode_transitions_nbw(m: int, q: Node, reach_func_desc: FuncDesc,
                            rank_func_desc: FuncDesc, tau_desc: FuncDesc,
                            desc_by_output: Dict[Signal, FuncDesc],
                            inputs: List[Signal]) -> List[str]:
    # syntax sugar
    def smt_r(smt_m: str, smt_q: str):
        return call_func(rank_func_desc, {
            ARG_MODEL_STATE: smt_m,
            ARG_A_STATE: smt_q
        })

    def smt_reach(smt_m: str, smt_q: str):
        return call_func(reach_func_desc, {
            ARG_MODEL_STATE: smt_m,
            ARG_A_STATE: smt_q
        })

    def smt_tau(smt_m: str, i_o: Label):
        tau_args = build_tau_args_dict(inputs, smt_m, i_o)
        return call_func(tau_desc, tau_args)

    # reach(q,t) ->
    #     OR{(q,io,q') \in \delta(q)}:
    #         sys_out=o & reach(q',t') & rank(q,t,q',t')

    s_m = smt_name_m(m)
    s_q = smt_name_q(q)
    s_pre = smt_reach(s_m, s_q)

    s_disjuncts = list()  # type: List[str]
    for lbl, qn_flag_pairs in q.transitions.items(
    ):  # type: (Label, Set[Tuple[Node, bool]])
        s_m_next = smt_tau(s_m, lbl)
        s_out = smt_out(s_m, lbl, inputs, desc_by_output)
        free_inputs = get_free_input_args(lbl, inputs)
        for (q_next, is_acc) in qn_flag_pairs:
            if is_final_sink(q_next):
                s_disj = exists_bool(free_inputs, s_out)
                s_disjuncts.append(s_disj)
                break
            s_q_next = smt_name_q(q_next)
            s_reach = smt_reach(s_m_next, s_q_next)
            if is_acc:
                s_rank = true()  # TODO: SCCs
            else:
                s_rank = op_gt(smt_r(s_m, s_q), smt_r(s_m_next, s_q_next))

            s_disj = exists_bool(free_inputs, op_and([s_out, s_reach, s_rank]))
            s_disjuncts.append(s_disj)

    s_assertion = op_implies(s_pre, op_or(s_disjuncts))
    return [assertion(s_assertion)]
示例#4
0
 def _encode_automata_functions(self) -> List[str]:
     aht_nodes = get_reachable_from(self.aht.init_node,
                                    self.aht_transitions,
                                    self.dstPropMgr)[0]
     return [
         declare_enum(TYPE_A_STATE, map(lambda n: smt_name_q(n), aht_nodes))
     ]
示例#5
0
    def encode_initialization(self) -> List[str]:
        q_init = self.aht.init_node
        m_init = self.model_init_state
        reach_args = {
            ARG_A_STATE: smt_name_q(q_init),
            ARG_MODEL_STATE: smt_name_m(m_init)
        }

        return [assertion(call_func(self.reach_func_desc, reach_args))]
示例#6
0
    def encode_run_graph(self, states_to_encode: Iterable[int]) -> List[str]:
        # state_to_rejecting_scc = build_state_to_rejecting_scc(self.automaton)

        res = []
        states, _ = get_reachable_from(self.aht.init_node,
                                       self.aht_transitions, self.dstPropMgr)
        for q in states:  # type: Node
            for m in states_to_encode:  # type: int
                res += [comment("encoding spec state '%s':" % smt_name_q(q))]
                res += self._encode_state(q, m)
        return res
示例#7
0
 def encode_initialization(self) -> List[str]:
     assertions = []
     for q, m in product(self.automaton.init_nodes,
                         [self.model_init_state]):
         vals_by_vars = {
             ARG_MODEL_STATE: smt_name_m(m),
             ARG_A_STATE: smt_name_q(q)
         }
         assertions.append(
             assertion(call_func(self.reach_func_desc, vals_by_vars)))
     return assertions
示例#8
0
 def _encode_prop_outputs(self) -> List[str]:
     res = []
     for pSig, func in self.desc_by_pSig.items():
         body = call_func(
             self.reach_func_desc, {
                 ARG_MODEL_STATE:
                 ARG_MODEL_STATE,
                 ARG_A_STATE:
                 smt_name_q(next(iter(self.atm_by_sig[pSig].init_nodes)))
             })
         res += [define_fun(func, body)]
     return res
示例#9
0
def encode_run_graph_ucw(reach_func_desc: FuncDesc, rank_func_desc: FuncDesc,
                         tau_desc: FuncDesc, desc_by_output: Dict[Signal,
                                                                  FuncDesc],
                         inputs: Iterable[Signal], automaton: Automaton,
                         states_to_encode: Iterable[int]) -> List[str]:
    inputs = list(inputs)
    state_to_rejecting_scc = build_state_to_final_scc(automaton)

    res = []
    for q in automaton.nodes:
        res.append(comment('encoding spec state ' + smt_name_q(q)))
        for m in states_to_encode:
            for label in q.transitions:
                res += _encode_transitions_ucw(reach_func_desc, rank_func_desc,
                                               tau_desc, desc_by_output,
                                               inputs, q, m, label,
                                               state_to_rejecting_scc)
    return res
示例#10
0
 def _encode_meaning_of_forbidding_atoms(self) -> List[str]:
     res = list()
     for k, a in enumerate(self.forbidding_atoms):
         states_to_forbid = set(
             filter(lambda n: n.k <= k, self.automaton.nodes))
         forbid_k_meaning = op_implies(
             a,
             op_and(
                 map(
                     lambda q_m: op_not(
                         call_func(
                             self.reach_func_desc, {
                                 ARG_A_STATE: smt_name_q(q_m[0]),
                                 ARG_MODEL_STATE: smt_name_m(q_m[1])
                             })),
                     product(states_to_forbid, self.max_model_states))))
         res.append(assertion(forbid_k_meaning))
     return res
示例#11
0
    def _encode_state(self, q: Node, m: int) -> List[str]:
        q_transitions = lfilter(lambda t: t.src == q, self.aht_transitions)

        # Encoding:
        # - if q is existential, then one of the transitions must fire:
        #
        #     reach(q,t) ->
        #                OR{state_label \in q_transitions}: sys_out=state_label & reach(q',t')
        #
        # - if q is universal, then all transitions of that system output should fire
        #
        #     reach(q,t) ->
        #                AND{state_label \in q_transitions}: sys_out=state_label -> reach(q',t')
        #

        # build s_premise `reach(q,t)`
        s_m = smt_name_m(m)
        s_q = smt_name_q(q)
        s_premise = call_func(self.reach_func_desc, {
            ARG_MODEL_STATE: s_m,
            ARG_A_STATE: s_q
        })

        # build s_conclusion `exists`
        s_conclusion_out_sExpr_pairs = set()  # type: Set[Tuple[str, str]]
        for t in q_transitions:  # type: Transition
            s_t_state_label = smt_out(s_m, t.state_label, self.inputs,
                                      self.descr_by_output)
            s_dst_expr = self._translate_dst_expr_into_smt(t.dst_expr, q, m)
            s_conclusion_out_sExpr_pairs.add((s_t_state_label, s_dst_expr))

        if q.is_existential:
            s_conclusion_elements = lmap(lambda sce: op_and(sce),
                                         s_conclusion_out_sExpr_pairs)
        else:
            s_conclusion_elements = lmap(
                lambda sce: op_implies(sce[0], sce[1]),
                s_conclusion_out_sExpr_pairs)

        s_conclusion = (op_and, op_or)[q.is_existential](s_conclusion_elements)

        s_assertion = op_implies(s_premise, s_conclusion)

        return [assertion(s_assertion)]