Пример #1
0
    def test_localize_two_ass_one_gua(self):
        """
        forall(i,j) a_i_j ->  forall(i) b_i
        replaced by
        forall(i,j) (a_i_j ->  b_i)
        """

        a_i_j_is_true, b_j_is_true = _get_is_true('a', 'i',
                                                  'j'), _get_is_true('b', 'j')
        b_i_is_true = _get_is_true('b', 'i')

        prop = SpecProperty([ForallExpr(['i', 'j'], a_i_j_is_true)],
                            [ForallExpr(['j'], b_j_is_true)])

        localized_prop = localize(prop)
        expected_prop_i_j1 = SpecProperty(
            [Bool(True)],
            [ForallExpr(['i', 'j'], BinOp('->', a_i_j_is_true, b_j_is_true))])
        expected_prop_i_j2 = SpecProperty(
            [Bool(True)],
            [ForallExpr(['i', 'j'], BinOp('->', a_i_j_is_true, b_i_is_true))])

        assert str(localized_prop) == str(expected_prop_i_j1) or \
               str(localized_prop) == str(expected_prop_i_j2), \
            str(localized_prop)
Пример #2
0
def strengthen(property:SpecProperty, ltl2ucw_converter) -> (list, list):
    """
    Return:
        'safety' properties (a_s -> g_s),
        'liveness' properties (a_s and a_l -> g_l)
    Also removes ground variables that becomes useless.
    """

    safety_properties = []
    liveness_properties = []

    denormalized_props = _get_denormalized_property(property)
    for p in denormalized_props:
        #: :type: SpecProperty
        p = p

        safety_ass = normalize_conjuncts([a for a in p.assumptions if is_safety(a, ltl2ucw_converter)])

        all_ass = normalize_conjuncts(p.assumptions)

        safety_guarantees = [g for g in p.guarantees if is_safety(g, ltl2ucw_converter)]
        liveness_guarantees = [g for g in p.guarantees if not is_safety(g, ltl2ucw_converter)]

        safety_properties += [SpecProperty([safety_ass], [sg])
                              for sg in safety_guarantees]
        liveness_properties += [SpecProperty([all_ass], [lg])
                                for lg in liveness_guarantees]

    return safety_properties, liveness_properties
Пример #3
0
    def test_instantiate_property_cutoff2(self):
        property = SpecProperty([Bool(True)], [parse_expr('Forall(j) b_j=1')])

        result = inst_property(property, 2)

        expected = SpecProperty([Bool(True)], [parse_expr('b_0=1')])

        result_data = _convert_conjunction_to_str(result)
        expected_data = _convert_conjunction_to_str(expected)

        self.assertEqual(expected_data, result_data)
Пример #4
0
    def test_instantiate_property_cutoff4(self):
        property = SpecProperty([parse_expr('Forall (i) a_i = 1')],
                                [parse_expr('Forall(j) b_j=1')])

        result = inst_property(property, 4)

        expected = SpecProperty([parse_expr('a_0=1 * a_1=1 * a_2=1 * a_3=1')],
                                [parse_expr('b_0=1')])

        result_data = _convert_conjunction_to_str(result)
        expected_data = _convert_conjunction_to_str(expected)

        self.assertEqual(expected_data, result_data)
Пример #5
0
    def test_instantiate_property_cutoff_another_4(self):
        property = SpecProperty([Bool(True)],
                                [parse_expr('Forall(j,k) b_j=1 -> c_k=1')])

        result = inst_property(property, 4)

        expected = SpecProperty([Bool(True)], [
            parse_expr(
                '(b_0=1 -> c_1=1) * (b_0=1 -> c_2=1) * (b_0=1 -> c_3=1)')
        ])

        result_data = _convert_conjunction_to_str(result)
        expected_data = _convert_conjunction_to_str(expected)

        self.assertEqual(expected_data, result_data)
Пример #6
0
    def test_strengthen3(self):
        """
        Forall(i,j) GFa_i * GFb_i_j * Gc_i_j -> Forall(k,m) GF(d_k_m) * G(e_k)
        replaced by
        'safety':   Forall(i) Gc_i_j  ->  Forall(k) G(e_k)
        'liveness': Forall(i,j) GFa_i * GFb_i_j * Gc_i  ->  Forall(k,m) GF(d_k_m)
        """
        a_i, b_i_j, c_i_j = _get_is_true('a', 'i'), _get_is_true(
            'b', 'i', 'j'), _get_is_true('c', 'i', 'j')
        ass = ForallExpr(['i', 'j'],
                         BinOp(
                             '*', UnaryOp('G', UnaryOp('F', a_i)),
                             BinOp('*', UnaryOp('G', UnaryOp('F', b_i_j)),
                                   UnaryOp('G', c_i_j))))

        d_k_m = _get_is_true('d', 'k', 'm')
        e_k = _get_is_true('e', 'k')
        gua = ForallExpr(['k', 'm'],
                         BinOp('*', UnaryOp('G', UnaryOp('F', d_k_m)),
                               UnaryOp('G', e_k)))

        property = SpecProperty([ass], [gua])
        safety_properties, liveness_properties = strengthen(
            property, self._get_converter())

        #lazy..
        print('safety_properties', safety_properties)
        assert len(safety_properties) == 1, str(safety_properties)
        assert len(list(chain(*[sp.assumptions
                                for sp in safety_properties]))) == 1
        assert len(list(chain(*[sp.guarantees
                                for sp in safety_properties]))) == 1

        print('liveness_properties', liveness_properties)
Пример #7
0
    def test_localize_zero_ass(self):
        """
        true -> forall(i) b_i
        replaced by
        forall(i) (true -> b_i)
        """

        b_i_is_true = _get_is_true('b', 'i')

        prop = SpecProperty([Bool(True)], [ForallExpr(['i'], b_i_is_true)])

        localized_prop = localize(prop)
        expected_prop = SpecProperty(
            [Bool(True)],
            [ForallExpr(['i'], BinOp('->', Bool(True), b_i_is_true))])

        assert str(localized_prop) == str(expected_prop), str(localized_prop)
Пример #8
0
def apply_log_bit_scheduler_optimization(instantiated_property:SpecProperty,
                                         scheduler:InterleavingScheduler,
                                         new_sched_signal_name:str,
                                         cutoff:int) -> SpecProperty:
    new_assumptions = [_apply_log_bit_optimization(new_sched_signal_name, a, cutoff, scheduler) for a in
                       instantiated_property.assumptions]
    new_guarantees = [_apply_log_bit_optimization(new_sched_signal_name, g, cutoff, scheduler) for g in
                      instantiated_property.guarantees]

    return SpecProperty(new_assumptions, new_guarantees)
Пример #9
0
    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)
Пример #10
0
def inst_property(property:SpecProperty, cutoff:int) -> SpecProperty:
    """
    forall(i,j) a_i_j -> forall(k) b_k
    =
    (!a_0_0 + !a_0_1 + !a_1_0 + !a_1_1 + ..) + (b_0*b_1*b_2..)
    where maximum values of i,j,k are defined by the min(max_cutoff, actual_cutoff).

    We optimize instantiations of guarantees by fixing one of the indices. E.g.:
    forall(i,j) a_i_j -> forall(k) b_k
    ~
    forall(i,j) a_i_j -> b_0
    (this is due to isomorphism of processes, TODO: make formal proof)


    NOTE on quantifier reordering:
    In the example above we can reorder quantifiers:
    forall exists (a+b) = exists forall (a+b)

    But in a general case it is not possible to reorder quantifiers --
    it depends on the formula quantified. E.g.:
    forall(k) exists(l) (a_k XOR b_l)
    !=
    exists(l) forall(k) (a_k XOR b_l)


    NOTE on 'forall instantiation' optimization:
    In the case above we can reorder quantifiers, and we assume that for the formulas of the form
     forall(i) a_i
     it is enough to verify a_0 (this assumption is due to symmetry, TODO: prove).
     Therefore we can instantiate only one guarantee:
     forall(i,j) a_i_j -> forall(i) b_i
     ~
     forall(i,j) a_i_j -> b_0

    NOTE on 'forall optimization' with two and more indices:
    If the property is "Forall(i,j) a_i_j",
     can it be replaced with 'a_0_0'?
    - No. Initially we give the token to a random process (on SMT level we have to tests all the possibilities).
    This means, that if we proved the property a_0 and process 0 is random <=> we proved Forall (i) a_0.
    In case of two indices Forall(i,j) a_i_j
    if we proved Forall(j) a_0_j with the same randomization <=> proved Forall(i,j) a_i_j,
    but it is incorrect to verify a_0_0 because it is equivalent to Forall (i) a_i_i.
    """

    assumptions = property.assumptions
    guarantees = [_set_one_index_to_zero(g) for g in property.guarantees]

    inst_assumptions = [_instantiate_expr(a, cutoff, False) for a in assumptions]
    inst_guarantees = [_instantiate_expr(g, cutoff, True) for g in guarantees]

    inst_p = SpecProperty(inst_assumptions, inst_guarantees)

    return inst_p
Пример #11
0
    def test_localize_one_ass_one_gua(self):
        """ forall(i) a_i -> forall(j) b_j
         replaced by
            forall(i) (a_i -> b_i)
        """

        prop = SpecProperty([parse_expr('Forall (i) a_i=1')],
                            [parse_expr('Forall (j) b_j=1')])

        localized_prop = localize(prop)
        expected_prop_i = SpecProperty(
            [Bool(True)], [parse_expr('Forall (i) a_i=1 -> b_i=1')])
        expected_prop_j = SpecProperty(
            [Bool(True)], [parse_expr('Forall (j) a_j=1 -> b_j=1')])

        expected_prop_str_i = str(expected_prop_i)
        expected_prop_str_j = str(expected_prop_j)
        localized_prop_str = str(localized_prop)

        assert localized_prop_str == expected_prop_str_i \
            or localized_prop_str == expected_prop_str_j, str(localized_prop_str)
Пример #12
0
def _replace_sched_by_true(spec_property: SpecProperty,
                           scheduler) -> SpecProperty:
    new_assumptions = [
        _replace_sched_in_expr_by_true(a, scheduler)
        for a in spec_property.assumptions
    ]
    new_guarantees = [
        _replace_sched_in_expr_by_true(g, scheduler)
        for g in spec_property.guarantees
    ]

    return SpecProperty(new_assumptions, new_guarantees)
Пример #13
0
def _get_denormalized_property(property:SpecProperty) -> list:
    """
    Property assumption may be of the form: forall(i) (safety_i and liveness_i)
    we introduce 'forall(i)' for each safety_i and liveness_i and therefore get:
    forall(i) safety_i and forall(i) liveness_i
    """

    denormalized_props = []

    denormalized_assumptions = list(chain(*[_denormalize(a) for a in property.assumptions]))
    denormalized_guarantees = list(chain(*[_denormalize(g) for g in property.guarantees]))

    for g in denormalized_guarantees:
        new_p = SpecProperty(denormalized_assumptions, [g])
        denormalized_props.append(new_p)

    return denormalized_props
Пример #14
0
def _get_acacia_spec(ltl_text: str, part_text: str,
                     logger: logging.Logger) -> (list, list, SpecProperty):
    input_signals, output_signals, data_by_name = acacia_parser.parse(
        ltl_text, part_text, logger)

    if data_by_name is None:
        return None, None, None

    spec_properties = []
    for (unit_name, unit_data) in data_by_name.items():
        assumptions = unit_data[0]
        guarantees = unit_data[1]
        spec_properties.append(SpecProperty(assumptions, guarantees))

    spec_property = and_properties(spec_properties)

    return input_signals, output_signals, spec_property
Пример #15
0
def localize(property:SpecProperty):
    """ sound, but incomplete
    forall(i) a_i -> forall(j) g_j
    =>
    forall(i) (a_i -> g_i)

    forall(i,j) a_i_j -> forall(k) g_k
    =>
    forall(i,j) (a_i_j -> g_i)
    """

    if not is_quantified_property(property):
        return property

    normalized_ass = normalize_conjuncts(property.assumptions)
    normalized_gua = normalize_conjuncts(property.guarantees)

    binding_indices_ass = _get_indices(normalized_ass)
    binding_indices_gua = _get_indices(normalized_gua)

    if len(binding_indices_ass) > len(binding_indices_gua):
        max_expr, other_expr = normalized_ass, normalized_gua
    else:
        max_expr, other_expr = normalized_gua, normalized_ass

    assert isinstance(max_expr, ForallExpr)

    max_binding_indices = max_expr.arg1

    ass_newindex_by_old = dict((o, max_binding_indices[i]) for i, o in enumerate(binding_indices_ass))
    gua_newindex_by_old = dict((o, max_binding_indices[i]) for i, o in enumerate(binding_indices_gua))

    replaced_ass = _replace_indices(ass_newindex_by_old, normalized_ass)
    replaced_gua = _replace_indices(gua_newindex_by_old, normalized_gua)

    replaced_underlying_ass = replaced_ass.arg2 if is_quantified_expr(replaced_ass) else replaced_ass
    replaced_underlying_gua = replaced_gua.arg2 if is_quantified_expr(replaced_gua) else replaced_gua

    new_gua = ForallExpr(max_binding_indices,
                         BinOp('->', replaced_underlying_ass, replaced_underlying_gua))

    new_property = SpecProperty([Bool(True)], [new_gua])

    return new_property
Пример #16
0
def _denormalize(conjunct:Expr) -> list:
    """
    Forall(i) a_i and b_i
    replaced by
    Forall(i) a_i and Forall(i) b_i
    """

    normalized_conjunct = normalize_conjuncts([conjunct])

    if not is_quantified_property(SpecProperty([normalized_conjunct], [])):
        return [normalized_conjunct]

    #: :type: ForallExpr
    forall_expr = conjunct
    quantified_expr = forall_expr.arg2

    conjunctions = _get_conjuncts(quantified_expr)

    return [_reduce_quantifiers(ForallExpr(forall_expr.arg1, c))
            for c in conjunctions]
Пример #17
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)
Пример #18
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])
Пример #19
0
def is_quantified_expr(expr: Expr):
    return is_quantified_property(SpecProperty([], [expr]))
Пример #20
0
def _get_automatae(assumptions, guarantees, optimization, cutoff,
                   ltl2ucw_converter: Ltl2UCW, logger):
    #TODO: check which optimizations are used

    properties = [SpecProperty(assumptions, [g]) for g in guarantees]
    logger.info('original properties:\n%s\n', '\n'.join(map(str, properties)))

    archi = TokRingArchitecture()
    archi_properties = [
        SpecProperty(assumptions, [g]) for g in archi.guarantees()
    ]
    logger.info('architecture properties:\n%s\n',
                '\n'.join(map(str, archi_properties)))

    if OPTS[optimization] >= OPTS[STRENGTH]:
        # we don't need this in case of async_hub since its assumptions implies GF(tok), put it is here for simplicity
        properties = [
            SpecProperty(p.assumptions + archi.implications(), p.guarantees)
            for p in properties
        ]

    properties = properties + archi_properties

    scheduler = InterleavingScheduler()
    properties = [
        SpecProperty(p.assumptions + scheduler.assumptions, p.guarantees)
        for p in properties
    ]
    logger.info('after updating with scheduling assumptions:\n%s\n',
                '\n'.join(map(str, properties)))

    #TODO: add support of using other options without using strengthening
    if OPTS[optimization] >= OPTS[STRENGTH]:
        logger.info('strengthening properties..')

        pseudo_safety_properties, pseudo_liveness_properties = strengthen_many(
            properties, ltl2ucw_converter)
        properties = pseudo_safety_properties + pseudo_liveness_properties

        logger.info(
            'strengthening resulted in pseudo_safety_properties (a_s -> g_s):\n%s\n',
            '\n'.join(map(str, pseudo_safety_properties)))
        logger.info(
            '..and in pseudo_liveness_properties (a_s&a_l -> g_l):\n%s\n',
            '\n'.join(map(str, pseudo_liveness_properties)))

    if OPTS[optimization] >= OPTS[STRENGTH]:
        properties = [localize(p) for p in properties]
        logger.info('properties after localizing:\n%s\n',
                    '\n'.join(map(str, properties)))

    prop_real_cutoff_pairs = [(p, archi.get_cutoff(p)) for p in properties]

    par_global_property_pairs = [(p, c) for (p, c) in prop_real_cutoff_pairs
                                 if c != 2]
    par_local_property_pairs = [(p, c) for (p, c) in prop_real_cutoff_pairs
                                if c == 2]
    for (p, c) in par_local_property_pairs:
        assert p.assumptions == [Bool(True)]
        assert c == 2

    if optimization == SYNC_HUB:  # removing GF(sch) from one-indexed properties
        par_local_property_pairs = [(_replace_sched_by_true(p, scheduler), c)
                                    for (p, c) in par_local_property_pairs]

    if optimization == SYNC_HUB:
        pass  # TODO: should add sync_hub assumptions -- but currently they are added on SMT (Impl) level

    if optimization == ASYNC_HUB:
        # by definition async_hub_assumptions are one-indexed
        async_hub_assumptions = archi.get_async_hub_assumptions()
        par_local_property_pairs = [
            (localize(SpecProperty(async_hub_assumptions, p.guarantees)), c)
            for (p, c) in par_local_property_pairs
        ]

    inst_property_cutoff_pairs = []
    for (p, c) in par_global_property_pairs + par_local_property_pairs:
        inst_c = min(c, cutoff)
        inst_p = inst_property(p, inst_c)
        opt_inst_p = apply_log_bit_scheduler_optimization(
            inst_p, scheduler, SCHED_ID_PREFIX, inst_c)

        inst_property_cutoff_pairs.append((opt_inst_p, c))

    local_properties = [p for (p, c) in inst_property_cutoff_pairs if c == 2]
    global_property_cutoff_pairs = [(p, min(c, cutoff))
                                    for (p, c) in inst_property_cutoff_pairs
                                    if p not in local_properties]

    logger.info('instantiated local properties:\n%s\n', local_properties)
    logger.info('instantiated global properties:\n%s\n',
                global_property_cutoff_pairs)

    local_automaton = None
    if len(local_properties) > 0:
        local_property = and_properties(local_properties)
        local_automaton = ltl2ucw_converter.convert(
            expr_from_property(local_property))

    glob_automatae_pairs = []
    if len(global_property_cutoff_pairs) > 0:
        glob_automatae_pairs = [
            (ltl2ucw_converter.convert(expr_from_property(p)), c)
            for (p, c) in global_property_cutoff_pairs
        ]

    if OPTS[optimization] < OPTS[SYNC_HUB] and local_automaton:
        if optimization == ASYNC_HUB:
            glob_automatae_pairs += [(local_automaton, 1)]
        else:
            glob_automatae_pairs += [(local_automaton, 2)]

    sync_automaton = None
    if OPTS[optimization] >= OPTS[SYNC_HUB]:
        sync_automaton = local_automaton

    return sync_automaton, glob_automatae_pairs
Пример #21
0
def _join_properties(properties: Iterable):
    properties = list(properties)
    all_ass = list(chain(p.assumptions for p in properties))
    all_gua = list(chain(p.guarantees for p in properties))
    return SpecProperty(all_ass, all_gua)