Beispiel #1
0
    def test_parse_ltl2ba_output__skip(self):
        text = """
            never { /* F(r && !g) */
            T0_init :    /* init */
                if
                :: (1) -> goto T0_init
                :: (r && !g) -> goto accept_all
                fi;
            accept_all :    /* 1 */
                skip
            }"""
        sig_g = QuantifiedSignal('g')
        sig_r = QuantifiedSignal('r')
        signal_by_name = {'r': sig_r, 'g': sig_g}
        initial_nodes, rejecting_nodes, nodes, _ = _get_hacked_ucw(
            text, signal_by_name)

        assert len(initial_nodes) == 1, str(len(initial_nodes))
        assert len(rejecting_nodes) == 1, str(len(rejecting_nodes))
        assert len(nodes) == 2, str(nodes)

        accept_all_node = [n for n in nodes if n.name == 'accept_all'][0]

        assert rejecting_nodes == {accept_all_node}
        assert len(accept_all_node.transitions) == 1

        label, dst_set_list = list(accept_all_node.transitions.items())[0]
        flagged_dst_set = dst_set_list[0]
        dst, is_rejecting = flagged_dst_set.pop()
        assert dst == accept_all_node, str(dst)
        assert label == {}, str(label)
def _instantiate(spec_text):
    section_by_name = parse_ltl(spec_text, logging.getLogger())
    input_signals = [QuantifiedSignal('r', i) for i in range(nof_processes)]
    output_signals = [QuantifiedSignal('g', i) for i in range(nof_processes)]

    assumptions = section_by_name[PAR_ASSUMPTIONS]
    guarantees = section_by_name[PAR_GUARANTEES]

    inst_assumptions = list(
        chain(
            *
            [_instantiate_expr2(a, nof_processes, False)
             for a in assumptions]))

    inst_guarantees = list(
        chain(
            *[_instantiate_expr2(g, nof_processes, False)
              for g in guarantees]))

    assumptions_as_strings = [
        ConverterToWringVisitor().dispatch(a) + ';\n' for a in inst_assumptions
    ]
    guarantees_as_strings = [
        ConverterToWringVisitor().dispatch(g) + ';\n' for g in inst_guarantees
    ]

    return input_signals, output_signals, assumptions_as_strings, guarantees_as_strings
Beispiel #3
0
    def test_parse_ltl2ba_output__or(self):
        text = """
            never {
            T0_init :    /* init */
                if
                :: (1) -> goto T0_init
                :: (r) || (!g) -> goto accept_all
                fi;
            accept_all :    /* 1 */
                skip
            }"""
        sig_g = QuantifiedSignal('g')
        sig_r = QuantifiedSignal('r')
        signal_by_name = {'r': sig_r, 'g': sig_g}
        initial_nodes, rejecting_nodes, nodes, _ = _get_hacked_ucw(
            text, signal_by_name)

        assert len(initial_nodes) == 1, str(len(initial_nodes))
        assert len(rejecting_nodes) == 1, str(len(rejecting_nodes))
        assert len(nodes) == 2, str(nodes)

        init_node = [n for n in nodes if n.name == 'T0_init'][0]

        assert len(init_node.transitions) == 3, len(init_node.transitions)

        for label, dst_set_list in init_node.transitions.items():
            assert len(dst_set_list) == 1, str(dst_set_list)
            flagged_dst_set = dst_set_list[0]
            for dst, is_rejecting in flagged_dst_set:
                assert (label == {} and dst == init_node) \
                           or (label == {sig_r: True} and dst != init_node) \
                    or (label == {sig_g: False} and dst != init_node)
Beispiel #4
0
 def _get_sync_impl(self, bound, init_process_states, local_automaton):
     impl = SyncImpl(
         local_automaton, not self._is_moore,
         [QuantifiedSignal(n, 0) for n in self._anon_input_names],
         [QuantifiedSignal(n, 0)
          for n in self._anon_output_names], bound, self._SYS_STATE_TYPE,
         QuantifiedSignal(self._names.has_tok_signal, 0),
         QuantifiedSignal(self._names.sends_signal, 0),
         QuantifiedSignal(self._names.sends_prev_signal, 0), self._TAU_NAME,
         init_process_states, self._underlying_solver)
     return impl
Beispiel #5
0
    def test_parse_ltl2ba_output(self):
        text = """
            never { /* !([](r -> <>g)) */
            T0_init :    /* init */
                if
                :: (1) -> goto T0_init
                :: (!g && r) -> goto accept_S2
                fi;
            accept_S2 :    /* 1 */
                if
                :: (!g) -> goto accept_S2
                fi;
            }"""

        sig_g = QuantifiedSignal('g')
        sig_r = QuantifiedSignal('r')
        signal_by_name = {'r': sig_r, 'g': sig_g}

        initial_nodes, rejecting_nodes, nodes, _ = _get_hacked_ucw(
            text, signal_by_name)

        assert len(initial_nodes) == 1, str(len(initial_nodes))
        assert len(rejecting_nodes) == 1, str(len(rejecting_nodes))
        assert len(nodes) == 2, str(nodes)

        for n in nodes:
            if n.name == 'T0_init':
                assert not n in rejecting_nodes
                assert n in initial_nodes
                assert len(n.transitions) == 2

                for label, dst_set_list in n.transitions.items():
                    assert len(dst_set_list) == 1, str(dst_set_list)
                    flagged_dst_set = dst_set_list[0]
                    for dst, is_rejecting in flagged_dst_set:
                        assert (dst.name == 'T0_init' and label == {}) or \
                               (dst.name == 'accept_S2' and label == {sig_g: False, sig_r: True}), \
                            'unknown transition: {0} {1}'.format(label, str(dst))

            elif n.name == 'accept_S2':
                assert n in rejecting_nodes
                assert not n in initial_nodes
                assert len(n.transitions) == 1

                for label, dst_set_list in n.transitions.items():
                    assert len(dst_set_list) == 1, str(dst_set_list)
                    flagged_dst_set = dst_set_list[0]
                    dst, is_rejecting = flagged_dst_set.pop()
                    assert dst.name == 'accept_S2' and label == {sig_g: False}
            else:
                assert False, 'unknown node: {0}'.format(str(n))
Beispiel #6
0
    def guarantees(self):
        """ Return G(tok_i -> Fsends_i)
        """
        #TODO: introduce Globally/Finally class
        expr = UnaryOp(
            'G',
            BinOp(
                '->', BinOp('=', QuantifiedSignal(HAS_TOK_NAME, 'i'),
                            Number(1)),
                UnaryOp(
                    'F',
                    BinOp('=', QuantifiedSignal(SENDS_NAME, 'i'), Number(1)))))

        tok_released = ForallExpr(['i'], expr)
        return [tok_released]
Beispiel #7
0
 def implications(self) -> list:
     expr = UnaryOp(
         'G',
         UnaryOp('F',
                 BinOp('=', QuantifiedSignal(HAS_TOK_NAME, 'i'),
                       Number(1))))
     fair_tok_sched = ForallExpr(['i'], expr)
     return [fair_tok_sched]
Beispiel #8
0
    def visit_signal(self, signal:Signal):
        if not isinstance(signal, QuantifiedSignal):
            return signal

        #noinspection PyUnresolvedReferences
        new_indices = self._replace(signal.binding_indices)

        new_signal = QuantifiedSignal(signal.name, *new_indices)
        return new_signal
    def test_strengthen2(self):
        """
        Forall(i) GFa_i and G(b_i)  ->  Forall(j) GF(c_j) and G(d_j)
        replaced by
        'liveness': Forall(i) GFa_i and G(b_i)  ->  Forall(j) GF(c_j)
        and
        'safety': Forall(i) G(b_i)  ->  Forall(j) G(d_j)
        """

        a_i, b_i = QuantifiedSignal('a', 'i'), QuantifiedSignal('b', 'i')
        c_j, d_j = QuantifiedSignal('c', 'j'), QuantifiedSignal('d', 'j')

        ass = ForallExpr(['i'],
                         BinOp('*', UnaryOp('G', UnaryOp('F', a_i)),
                               UnaryOp('G', b_i)))
        gua = ForallExpr(['j'],
                         BinOp('*', UnaryOp('G', UnaryOp('F', c_j)),
                               UnaryOp('G', d_j)))

        property = SpecProperty([ass], [gua])

        safety_properties, liveness_properties = strengthen(
            property, self._get_converter())

        assert len(liveness_properties) == 1, str(liveness_properties)
        assert len(safety_properties) == 1, str(safety_properties)

        expected_liveness_gua = ForallExpr(['j'],
                                           UnaryOp('G', UnaryOp('F', c_j)))

        #: :type: SpecProperty
        liveness_prop = liveness_properties[0]
        assert str(liveness_prop.assumptions) == str([ass]), str(liveness_prop)
        assert str(liveness_prop.guarantees) == str([expected_liveness_gua])

        safety_prop = safety_properties[0]
        expected_safety_ass = ForallExpr(['i'], UnaryOp('G', b_i))
        expected_safety_gua = ForallExpr(['j'], UnaryOp('G', d_j))
        expected_safety_prop = SpecProperty([expected_safety_ass],
                                            [expected_safety_gua])
        assert str(expected_safety_prop) == str(safety_prop), str(safety_prop)
Beispiel #10
0
    def test_strengthen2(self):
        """
        Forall(i) GFa_i -> Forall(j) GF(b_j)
        is left as it is
        """
        a_i, b_j = QuantifiedSignal('a', 'i'), QuantifiedSignal('b', 'j')

        liveness_ass = ForallExpr(['i'], UnaryOp('G', UnaryOp('F', a_i)))
        liveness_gua = ForallExpr(['j'], UnaryOp('G', UnaryOp('F', b_j)))

        property = SpecProperty([liveness_ass], [liveness_gua])

        safety_properties, liveness_properties = strengthen(
            property, self._get_converter())

        assert len(liveness_properties) == 1, str(liveness_properties)
        assert len(safety_properties) == 0, str(safety_properties)

        actual = liveness_properties[0]
        expected = property
        assert str(actual) == str(
            expected), str(actual) + ' vs ' + str(expected)
Beispiel #11
0
    def test_strengthen1(self):
        """
        Forall(i) GFa_i -> Forall(j) G(b_j)
        replaced by
        'safety': Forall(j) G(b_j)
        'liveness': []
        """

        a_i, b_j = QuantifiedSignal('a', 'i'), QuantifiedSignal('b', 'j')

        liveness_ass = ForallExpr(['i'], UnaryOp('G', UnaryOp('F', a_i)))
        safety_gua = ForallExpr(['j'], UnaryOp('G', b_j))

        property = SpecProperty([liveness_ass], [safety_gua])

        safety_properties, liveness_properties = strengthen(
            property, self._get_converter())

        assert len(liveness_properties) == 0, str(liveness_properties)
        assert len(safety_properties) == 1, str(safety_properties)

        actual_guarantees = safety_properties[0].guarantees
        assert str(actual_guarantees) == str([safety_gua]), \
            '\n' + str(actual_guarantees) + '\nvs\n' + str([safety_gua])
Beispiel #12
0
    def tests_all(self):
        input_signals, output_signals, data_by_name = parse(
            test_string_ltl, test_string_part, logging.getLogger())

        exp_input_signals = [
            QuantifiedSignal(n, 0) for n in 'idle request0 request1'.split()
        ]
        assert set(input_signals) == set(exp_input_signals)

        exp_output_signals = [
            QuantifiedSignal(n, 0) for n in 'grant0 grant1'.split()
        ]
        assert set(output_signals) == set(exp_output_signals)

        for (k, v) in data_by_name.items():
            print(k, v)

        u1_assumptions, u1_guarantees = data_by_name['u1']
        assert len(u1_assumptions) == 1
        assert len(u1_guarantees) == 3

        u2_assumptions, u2_guarantees = data_by_name['u2']
        assert len(u2_assumptions) == 2
        assert len(u2_guarantees) == 3
Beispiel #13
0
def _get_log_encoded_expr(signal:QuantifiedSignal, new_sched_signal_name:str, cutoff:int) -> Expr:
    assert len(signal.binding_indices) == 1

    proc_index = signal.binding_indices[0]

    nof_sched_bits = int(max(1, math.ceil(math.log(cutoff, 2))))
    bits = bin_fixed_list(proc_index, nof_sched_bits)

    #TODO: use quantified signal or signal?
    conjuncts = [BinOp('=',
                       QuantifiedSignal(new_sched_signal_name, bit_index),
                       Number(1 if bit_value else 0))
                 for bit_index, bit_value in enumerate(bits)]

    conjunction = and_expressions(conjuncts)

    return conjunction
Beispiel #14
0
    def _get_par_impl(self, automaton: Automaton, model_size: int,
                      nof_processes: int, sys_intern_funcs_postfix):

        sched_input_signals = get_signals_definition(
            self._names.sched_signal, get_log_bits(nof_processes))[0]
        is_active_signals = [
            QuantifiedSignal(self._names.active_signal, i)
            for i in range(nof_processes)
        ]
        sends_signals = [
            QuantifiedSignal(self._names.sends_signal, i)
            for i in range(nof_processes)
        ]
        sends_prev_signals = [
            QuantifiedSignal(self._names.sends_prev_signal, i)
            for i in range(nof_processes)
        ]
        has_tok_signals = [
            QuantifiedSignal(self._names.has_tok_signal, i)
            for i in range(nof_processes)
        ]

        orig_input_signals = [
            QuantifiedSignal(n, i)
            for (n, i) in product(self._anon_input_names, range(nof_processes))
        ]
        orig_output_signals = [
            QuantifiedSignal(n, i)
            for (n,
                 i) in product(self._anon_output_names, range(nof_processes))
        ]

        par_impl = ParImpl(automaton, not self._is_moore, orig_input_signals,
                           orig_output_signals, nof_processes, model_size,
                           sched_input_signals, is_active_signals,
                           sends_signals, sends_prev_signals, has_tok_signals,
                           self._SYS_STATE_TYPE, self._TAU_NAME,
                           sys_intern_funcs_postfix, self._underlying_solver)
        return par_impl
Beispiel #15
0
def _parse_signals_from_lines(signal_lines: list) -> list:
    signals_raw = chain(*[l.split()[1:] for l in signal_lines])

    signals = [QuantifiedSignal(n.strip(), 0) for n in signals_raw]

    return signals
Beispiel #16
0
def _get_is_value(signal_name: str, value: Number, *binding_indices):
    if len(binding_indices) == 0:
        signal = Signal(signal_name)
    else:
        signal = QuantifiedSignal(signal_name, *binding_indices)
    return BinOp('=', signal, value)
Beispiel #17
0
def get_signals_definition(signal_base_name, nof_bits):
    signals = list(
        map(lambda i: QuantifiedSignal(signal_base_name, i), range(nof_bits)))
    args_defs = list(map(lambda s: (s, 'Bool'), signals))
    return signals, args_defs
Beispiel #18
0
    def __init__(
            self,
            automaton: Automaton,
            is_mealy: bool,
            orig_inputs,
            orig_outputs,
            nof_processes: int,
            nof_local_states: int,
            sched_inputs,
            is_active_signals,
            sends_signals,
            sends_prev_signals,
            #sends_prev is input signals, sends_signals are output, though essentially they are the same
            has_tok_signals,  # it is part of the state, but can be emulated as Moore-like output signal
            state_type,
            tau_name,
            internal_funcs_postfix: str,
            underlying_solver: SolverInterface):

        super().__init__(is_mealy, underlying_solver)

        for s in orig_inputs:  # TODO: remove me after debug
            assert isinstance(s, QuantifiedSignal)
            assert 'prev' not in s.name, str(s)

        for s in orig_outputs:  # TODO: remove me after debug
            assert isinstance(s, QuantifiedSignal)
            assert 'prev' not in s.name, str(s)
            assert 'tok' not in s.name, str(s)

        self.automaton = automaton
        self.nof_processes = nof_processes

        self._state_type = state_type

        self._has_tok_signals = has_tok_signals
        self._sends_prev_signals = sends_prev_signals
        self._sends_signals = sends_signals
        self._is_active_signals = is_active_signals

        self._TAU_NAME = tau_name
        self._IS_ACTIVE_NAME = 'is_active' + internal_funcs_postfix
        self._EQUAL_BITS_NAME = 'equal_bits' + internal_funcs_postfix
        self._PREV_IS_SCHED_NAME = 'prev_is_sched' + internal_funcs_postfix
        self._NEXT_IS_SCHED_NAME = 'next_is_sched' + internal_funcs_postfix
        self._TAU_SCHED_WRAPPER_NAME = 'tau_sch' + internal_funcs_postfix
        self._PROC_ID_PREFIX = 'proc'  # TODO: check necessity

        self._nof_proc_bits = get_log_bits(nof_processes)

        self._sched_signals = sched_inputs  # TODO: check necessity
        self._sched_arg_type_pairs = [(s, 'Bool') for s in self._sched_signals]

        #intoduced proc_signals to resemble sched_signals
        self._proc_signals = [
            QuantifiedSignal(self._PROC_ID_PREFIX, i)
            for i in range(get_log_bits(nof_processes))
        ]
        self._proc_arg_type_pairs = [(s, 'Bool') for s in self._proc_signals]

        self._equals_first_args, _ = get_signals_definition(
            'x', self._nof_proc_bits)
        self._equals_second_args, _ = get_signals_definition(
            'y', self._nof_proc_bits)

        ### BlankImpl interface TODO: use __init__ with arguments?
        self.states_by_process = self.nof_processes * [
            tuple(
                self.get_state_name(self._state_type, i)
                for i in range(nof_local_states))
        ]
        self.state_types_by_process = self.nof_processes * [self._state_type]

        archi_inputs = sends_prev_signals
        archi_outputs = has_tok_signals + sends_signals

        all_models_inputs = orig_inputs + archi_inputs
        #TODO: rename to self.model_inputs
        self.orig_inputs = _build_model_inputs(nof_processes,
                                               all_models_inputs)

        self.init_states = self._build_init_states()
        self.outvar_desc_by_process = [
            self._build_desc_by_out(_filter_by_proc(i, orig_outputs),
                                    _filter_by_proc(i, archi_outputs),
                                    _filter_by_proc(i, all_models_inputs))
            for i in range(nof_processes)
        ]
        self.aux_func_descs_ordered = self._build_aux_func_descs()

        self.taus_descs = self._build_taus_descs(all_models_inputs)
        self.model_taus_descs = self._build_model_taus_descs(all_models_inputs)
Beispiel #19
0
 def assumptions(self):
     return [ForallExpr(['i'],
                        UnaryOp('G', UnaryOp('F',
                                             BinOp('=',
                                                   QuantifiedSignal(self._FAIR_SCHED_NAME, 'i'),
                                                   Number(1)))))]