Ejemplo n.º 1
0
def test_delta():
    parser = LDLfParser()
    sa, sb, sc = "A", "B", "C"
    a, b, c = PLAtomic(sa), PLAtomic(sb), PLAtomic(sc)

    i_ = PLFalseInterpretation()
    i_a = PLInterpretation({sa})
    i_b = PLInterpretation({sb})
    i_ab = PLInterpretation({sa, sb})

    true = PLTrue()
    false = PLFalse()
    tt = LDLfLogicalTrue()
    ff = LDLfLogicalFalse()

    assert parser("<A>tt").delta(i_) == false
    assert parser("<A>tt").delta(i_a) == PLAtomic(tt)
    assert parser("<A>tt").delta(i_b) == false
    assert parser("<A>tt").delta(i_ab) == PLAtomic(tt)

    assert parser("[B]ff").delta(i_) == true
    assert parser("[B]ff").delta(i_a) == true
    assert parser("[B]ff").delta(i_b) == PLAtomic(ff)
    assert parser("[B]ff").delta(i_ab) == PLAtomic(ff)

    f = parser("!(<!(A<->B)+(B;A)*+(!last)?>[(true)*]end)")
    assert f.delta(i_) == f.to_nnf().delta(i_)
    assert f.delta(i_ab) == f.to_nnf().delta(i_ab)

    assert f.delta(i_, epsilon=True) == f.to_nnf().delta(i_, epsilon=True)
    assert f.delta(i_ab, epsilon=True) == f.to_nnf().delta(i_ab, epsilon=True)
    # with epsilon=True, the result is either PLTrue or PLFalse
    assert f.delta(i_, epsilon=True) in [PLTrue(), PLFalse()]
Ejemplo n.º 2
0
def test_delta():
    parser = LDLfParser()
    i_ = {}
    i_a = {"A": True}
    i_b = {"B": True}
    i_ab = {"A": True, "B": True}

    true = PLTrue()
    false = PLFalse()
    tt = PLAtomic(LDLfLogicalTrue())
    ff = PLAtomic(LDLfLogicalFalse())

    assert parser("<A>tt").delta(i_) == false
    assert parser("<A>tt").delta(i_a) == tt
    assert parser("<A>tt").delta(i_b) == false
    assert parser("<A>tt").delta(i_ab) == tt

    assert parser("[B]ff").delta(i_) == true
    assert parser("[B]ff").delta(i_a) == true
    assert parser("[B]ff").delta(i_b) == ff
    assert parser("[B]ff").delta(i_ab) == ff

    f = parser("!(<?(!last)>end)")
    assert f.delta(i_) == f.to_nnf().delta(i_)
    assert f.delta(i_ab) == f.to_nnf().delta(i_ab)

    assert f.delta(i_, epsilon=True) == f.to_nnf().delta(i_, epsilon=True)
    assert f.delta(i_ab, epsilon=True) == f.to_nnf().delta(i_ab, epsilon=True)
    # with epsilon=True, the result is either PLTrue or PLFalse
    assert f.delta(i_, epsilon=True) in [PLTrue(), PLFalse()]
Ejemplo n.º 3
0
 def delta_box(self, f: LDLfFormula, i: PLInterpretation, epsilon=False):
     if epsilon:
         return PLTrue()
     if self.pl_formula.truth(i):
         return PLAtomic(_expand(f))
     else:
         return PLTrue()
Ejemplo n.º 4
0
    def test_misc(self):
        a, b = self.a, self.b
        i_, i_a, i_b, i_ab = self.i_, self.i_a, self.i_b, self.i_ab

        material_implication = PLEquivalence(
            [PLOr([PLNot(a), b]), PLNot(PLAnd([a, PLNot(b)])), PLImplies([a, b])]
        )

        # the equivalence is valid (i.e. satisfied for every interpretation)
        assert material_implication.truth(i_)
        assert material_implication.truth(i_a)
        assert material_implication.truth(i_b)
        assert material_implication.truth(i_ab)

        a_and_false_and_true = PLAnd([a, PLFalse(), PLTrue()])
        assert not a_and_false_and_true.truth(i_)
        assert not a_and_false_and_true.truth(i_a)
        assert not a_and_false_and_true.truth(i_b)
        assert not a_and_false_and_true.truth(i_ab)

        a_or_false_or_true = PLOr([a, PLFalse(), PLTrue()])
        assert a_or_false_or_true.truth(i_)
        assert a_or_false_or_true.truth(i_a)
        assert a_or_false_or_true.truth(i_b)
        assert a_or_false_or_true.truth(i_ab)
Ejemplo n.º 5
0
 def delta(self, i: PLInterpretation, epsilon=False) -> PLFormula:
     f = self.to_nnf()
     d = f._delta(i, epsilon)
     if epsilon:
         # By definition, if epsilon=True, then the result must be either PLTrue or PLFalse
         # Now, the output is a Propositional Formula with only PLTrue or PLFalse as atomics
         # Hence, we just evaluate the formula with a dummy PLInterpretation
         d = PLTrue() if d.truth(None) else PLFalse()
     return d
Ejemplo n.º 6
0
    def _delta(self, i: PropositionalInterpretation, epsilon=False):
        """Apply the delta function."""
        if epsilon:
            return PLFalse()

        result = self.f._delta(i, epsilon=epsilon)
        if result == PLTrue():
            return PLFalse()
        else:
            return PLTrue()
Ejemplo n.º 7
0
 def delta_box(self,
               f: LDLfFormula,
               i: PropositionalInterpretation,
               epsilon=False):
     """Apply delta function for regular expressions in the box operator."""
     if epsilon:
         return PLTrue()
     if self.pl_formula.truth(i):
         return PLAtomic(_expand(f))
     else:
         return PLTrue()
Ejemplo n.º 8
0
 def delta(self,
           i: PropositionalInterpretation,
           epsilon=False) -> PLFormula:
     """Apply the delta function."""
     f = self.to_nnf()
     d = f._delta(i, epsilon=epsilon)
     if epsilon:
         # By definition, if epsilon=True, then the result must be either True or False.
         # The output is a Propositional Formula with only True or False as atomics.
         # Hence, we just evaluate the formula with the empty propositional interpretation.
         d = PLTrue() if d.truth({}) else PLFalse()
     return d
Ejemplo n.º 9
0
 def p_propositional(self, p):
     """propositional : propositional EQUIVALENCE propositional
                      | propositional IMPLIES propositional
                      | propositional OR propositional
                      | propositional AND propositional
                      | NOT propositional
                      | FALSE
                      | TRUE
                      | ATOM"""
     if len(p)==4:
         if p[2] == Symbols.EQUIVALENCE.value:
             p[0] = PLEquivalence([p[1], p[3]])
         elif p[2] == Symbols.IMPLIES.value:
             p[0] = PLImplies([p[1], p[3]])
         elif p[2] == Symbols.OR.value:
             p[0] = PLOr([p[1], p[3]])
         elif p[2] == Symbols.AND.value:
             p[0] = PLAnd([p[1], p[3]])
         else:
             raise ValueError
         # else:
         #     p[0] = p[2]
     elif len(p)==3:
         p[0] = PLNot(p[2])
     elif len(p)==2:
         if p[1]==Symbols.TRUE.value:
             p[0] = PLTrue()
         elif p[1]==Symbols.FALSE.value:
             p[0] = PLFalse()
         else:
             p[0] = PLAtomic(p[1])
     else:
         raise ValueError
Ejemplo n.º 10
0
def to_automaton(f) -> SymbolicDFA:  # noqa: C901
    """Translate to automaton."""
    f = f.to_nnf()
    initial_state = frozenset({frozenset({PLAtomic(f)})})
    states = {initial_state}
    final_states = set()
    transition_function = {}  # type: Dict

    all_labels = f.find_labels()
    alphabet = powerset(all_labels)

    if f.delta({}, epsilon=True) == PLTrue():
        final_states.add(initial_state)

    visited = set()  # type: Set
    to_be_visited = {initial_state}

    while len(to_be_visited) != 0:

        for q in list(to_be_visited):
            to_be_visited.remove(q)
            for actions_set in alphabet:
                new_state = _make_transition(
                    q, {label: True
                        for label in actions_set})
                if new_state not in states:
                    states.add(new_state)
                    to_be_visited.add(new_state)

                transition_function.setdefault(q, {})[actions_set] = new_state

                if new_state not in visited:
                    visited.add(new_state)
                    if _is_true(new_state):
                        final_states.add(new_state)

    automaton = SymbolicAutomaton()
    state2idx = {}
    for state in states:
        state_idx = automaton.create_state()
        state2idx[state] = state_idx
        if state == initial_state:
            automaton.set_initial_state(state_idx)
        if state in final_states:
            automaton.set_accepting_state(state_idx, True)

    for source in transition_function:
        for symbol, destination in transition_function[source].items():
            source_idx = state2idx[source]
            dest_idx = state2idx[destination]
            pos_expr = sympy.And(*map(sympy.Symbol, symbol))
            neg_expr = sympy.And(*map(lambda x: sympy.Not(sympy.Symbol(x)),
                                      all_labels.difference(symbol)))
            automaton.add_transition(
                (source_idx, sympy.And(pos_expr, neg_expr), dest_idx))

    determinized = automaton.determinize()
    minimized = determinized.minimize()
    return minimized
Ejemplo n.º 11
0
 def to_LDLf(self):
     f1 = self.formulas[0].to_LDLf()
     f2 = LTLfUntil(self.formulas[1:]).to_LDLf() if len(
         self.formulas) > 2 else self.formulas[1].to_LDLf()
     return LDLfDiamond(
         RegExpStar(
             RegExpSequence([RegExpTest(f1),
                             RegExpPropositional(PLTrue())])),
         LDLfAnd([f2, LDLfNot(LDLfEnd())]))
Ejemplo n.º 12
0
 def _delta(self, i: PLInterpretation, epsilon=False):
     if isinstance(self.f, LTLfAtomic) or isinstance(self.f, LTLfEnd):
         if epsilon:
             return PLFalse()
         else:
             return PLTrue() if self.f._delta(
                 i, epsilon) == PLFalse() else PLFalse()
     else:
         # the formula must be in NNF form!!!
         raise Exception
Ejemplo n.º 13
0
 def p_formula_atom(self, p):
     """formula : ATOM
                | TRUE
                | FALSE"""
     if p[1] == Symbols.TRUE.value:
         p[0] = PLTrue()
     elif p[1] == Symbols.FALSE.value:
         p[0] = PLFalse()
     else:
         p[0] = PLAtomic(p[1])
Ejemplo n.º 14
0
 def _delta(self, i: PLInterpretation, epsilon=False):
     if epsilon:
         return PLTrue()
     f1 = self.formulas[0]
     f2 = LTLfRelease(
         self.formulas[1:]) if len(self.formulas) > 2 else self.formulas[1]
     return PLAnd([
         f2._delta(i, epsilon),
         PLOr(
             [f1._delta(i, epsilon),
              LTLfWeakNext(self)._delta(i, epsilon)])
     ])
Ejemplo n.º 15
0
 def _delta(self, i: PropositionalInterpretation, epsilon=False):
     """Apply the delta function."""
     if epsilon:
         return PLTrue()
     f1 = self.formulas[0]
     f2 = (LTLfRelease(self.formulas[1:])
           if len(self.formulas) > 2 else self.formulas[1])
     return PLAnd([
         f2._delta(i, epsilon),
         PLOr(
             [f1._delta(i, epsilon),
              LTLfWeakNext(self)._delta(i, epsilon)]),
     ])
Ejemplo n.º 16
0
def _make_transition(Q: FrozenSet[FrozenSet[PLAtomic]], i: PLInterpretation):
    actions_set = i.true_propositions
    new_macrostate = set()

    for q in Q:
        # delta function applied to every formula in the macro state Q
        delta_formulas = [f.s.delta(actions_set) for f in q]

        # find the list of atoms, which are "true" atoms (i.e. propositional atoms) or LDLf formulas
        atomics = [s for subf in delta_formulas for s in find_atomics(subf)]

        atom2id = {v: k
                   for k, v in enumerate(atomics)}  # type: Dict[int, PLAtomic]
        id2atom = {v: k
                   for k, v in atom2id.items()}  # type: Dict[PLAtomic, int]

        # "freeze" the found atoms as symbols and build a mapping from symbols to formulas
        symbol2formula = {
            atom2id[f]
            for f in atomics if f != PLTrue() and f != PLFalse()
        }

        # build a map from formula to a "freezed" propositional Atomic Formula
        formula2atomic_formulas = {
            f: PLAtomic(atom2id[f]) if f != PLTrue()
            and f != PLFalse()  # and not isinstance(f, PLAtomic)
            else f
            for f in atomics
        }

        # the final list of Propositional Atomic Formulas, one for each formula in the original macro state Q
        transformed_delta_formulas = [
            _transform_delta(f, formula2atomic_formulas)
            for f in delta_formulas
        ]

        # the empty conjunction stands for true
        if len(transformed_delta_formulas) == 0:
            conjunctions = PLTrue()
        elif len(transformed_delta_formulas) == 1:
            conjunctions = transformed_delta_formulas[0]
        else:
            conjunctions = PLAnd(transformed_delta_formulas)

        # the model in this case is the smallest set of symbols s.t. the conjunction of "freezed" atomic formula
        # is true.
        alphabet = frozenset(symbol2formula)
        models = frozenset(conjunctions.minimal_models(alphabet))

        for min_model in models:
            q_prime = frozenset(
                {id2atom[s]
                 for s in min_model.true_propositions})

            new_macrostate.add(q_prime)

    return frozenset(new_macrostate)
Ejemplo n.º 17
0
 def setup_class(cls):
     cls.parser = LTLfParser()
     cls.i_, cls.i_a, cls.i_b, cls.i_ab = (
         {},
         {
             "a": True
         },
         {
             "b": True
         },
         {
             "a": True,
             "b": True
         },
     )
     cls.true = PLTrue()
     cls.false = PLFalse()
Ejemplo n.º 18
0
def test_parser():
    parser = PLParser()
    sa, sb = "A", "B"
    a, b = PLAtomic(sa), PLAtomic(sb)

    a_and_b = parser("A & B")
    true_a_and_b = PLAnd([a, b])
    assert a_and_b == true_a_and_b

    material_implication = parser("!A | B <-> !(A & !B) <-> A->B")
    true_material_implication = PLEquivalence(
        [PLOr([PLNot(a), b]), PLNot(PLAnd([a, PLNot(b)])), PLImplies([a, b])]
    )

    assert material_implication == true_material_implication

    true_a_and_false_and_true = PLAnd([a, PLFalse(), PLTrue()])
    a_and_false_and_true = parser("A & false & true")

    assert a_and_false_and_true == true_a_and_false_and_true
Ejemplo n.º 19
0
def to_automaton(f, labels: Optional[Set[Symbol]] = None):

    initial_state = frozenset({frozenset({PLAtomic(f)})})
    states = {initial_state}
    final_states = set()
    transition_function = {}

    # the alphabet is the powerset of the set of fluents
    alphabet = powerset(labels if labels is not None else f.find_labels())

    if f.delta(PLFalseInterpretation(), epsilon=True) == PLTrue():
        final_states.add(initial_state)

    visited = set()
    to_be_visited = {initial_state}

    while len(to_be_visited) != 0:

        for q in list(to_be_visited):
            to_be_visited.remove(q)
            for actions_set in alphabet:
                new_state = _make_transition(q, PLInterpretation(actions_set))
                if new_state not in states:
                    states.add(new_state)
                    to_be_visited.add(new_state)

                transition_function.setdefault(
                    q, {})[PLInterpretation(actions_set)] = new_state

                if new_state not in visited:
                    visited.add(new_state)
                    if _is_true(new_state):
                        final_states.add(new_state)

    new_alphabet = {PLInterpretation(set(sym)) for sym in alphabet}
    dfa = DFA(states, new_alphabet, initial_state, final_states,
              transition_function)
    dfa = dfa.minimize()
    dfa = dfa.trim()

    return dfa
Ejemplo n.º 20
0
 def _delta(self, i: PLInterpretation, epsilon: bool = False):
     if epsilon:
         return PLFalse()
     return PLTrue() if PLAtomic(self.s).truth(i) else PLFalse()
Ejemplo n.º 21
0
 def _delta(self, i: PLInterpretation, epsilon=False):
     return PLTrue()
Ejemplo n.º 22
0
 def to_LDLf(self):
     return LDLfDiamond(RegExpStar(RegExpPropositional(PLTrue())),
                        LDLfAnd([self.f.to_LDLf(),
                                 LDLfNot(LDLfEnd())]))
Ejemplo n.º 23
0
 def _delta(self, i: PLInterpretation, epsilon=False):
     if epsilon:
         return PLTrue()
     else:
         return PLOr([PLAtomic(self.f), PLAtomic(LTLfEnd().to_nnf())])
Ejemplo n.º 24
0
def test_parser():
    parser = LDLfParser()
    a, b = PLAtomic("A"), PLAtomic("B")

    tt = LDLfLogicalTrue()
    ff = LDLfLogicalFalse()
    true = PLTrue()
    false = PLFalse()
    r_true = RegExpPropositional(true)
    r_false = RegExpPropositional(false)

    assert tt == parser("tt")
    assert ff == parser("ff")
    assert LDLfDiamond(r_true, tt) == parser("<true>tt")
    assert LDLfDiamond(r_false, tt) == parser("<false>tt")
    assert parser("!tt & <!A&B>tt") == LDLfAnd([
        LDLfNot(tt),
        LDLfDiamond(RegExpPropositional(PLAnd([PLNot(a), b])), tt)
    ])
    assert parser("[true*]([true]ff | <!A>tt | <(true)*><B>tt)") == LDLfBox(
        RegExpStar(r_true),
        LDLfOr([
            LDLfBox(r_true, ff),
            LDLfDiamond(RegExpPropositional(PLNot(a)), tt),
            LDLfDiamond(RegExpStar(r_true),
                        (LDLfDiamond(RegExpPropositional(b), tt))),
        ]),
    )

    assert parser("[A&B&A]ff <-> <A&B&A>tt") == LDLfEquivalence([
        LDLfBox(RegExpPropositional(PLAnd([a, b, a])), ff),
        LDLfDiamond(RegExpPropositional(PLAnd([a, b, a])), tt),
    ])

    assert parser("<A+B>tt") == LDLfDiamond(
        RegExpUnion([RegExpPropositional(a),
                     RegExpPropositional(b)]), tt)
    assert parser("<A;B>tt") == LDLfDiamond(
        RegExpSequence([RegExpPropositional(a),
                        RegExpPropositional(b)]), tt)
    assert parser("<A+(B;A)>end") == LDLfDiamond(
        RegExpUnion([
            RegExpPropositional(a),
            RegExpSequence([RegExpPropositional(b),
                            RegExpPropositional(a)]),
        ]),
        LDLfEnd(),
    )

    assert parser("!(<(!(A<->D))+((B;C)*)+(?!last)>[(true)*]end)") == LDLfNot(
        LDLfDiamond(
            RegExpUnion([
                RegExpPropositional(PLNot(PLEquivalence([a, PLAtomic("D")]))),
                RegExpStar(
                    RegExpSequence([
                        RegExpPropositional(PLAtomic("B")),
                        RegExpPropositional(PLAtomic("C")),
                    ])),
                RegExpTest(LDLfNot(LDLfLast())),
            ]),
            LDLfBox(RegExpStar(RegExpPropositional(PLTrue())), LDLfEnd()),
        ))
Ejemplo n.º 25
0
 def _delta(self, i: PLInterpretation, epsilon: bool = False):
     if epsilon:
         return PLFalse()
     else:
         return PLTrue()
Ejemplo n.º 26
0
 def prop_true(self, args):
     assert len(args) == 1
     return PLTrue()
Ejemplo n.º 27
0
 def _delta(self, i: PropositionalInterpretation, epsilon: bool = False):
     """Apply the delta function."""
     if epsilon:
         return PLFalse()
     return PLTrue() if PLAtomic(self.s).truth(i) else PLFalse()
Ejemplo n.º 28
0
 def _delta(self, i: PropositionalInterpretation, epsilon=False):
     """Apply the delta function."""
     if epsilon:
         return PLTrue()
     else:
         return PLOr([PLAtomic(self.f), PLAtomic(LTLfEnd().to_nnf())])
Ejemplo n.º 29
0
def _make_transition(marco_q: FrozenSet[FrozenSet[PLAtomic]],
                     i: PropositionalInterpretation):
    new_macrostate = set()

    for q in marco_q:
        # delta function applied to every formula in the macro state Q
        delta_formulas = [cast(Delta, f.s).delta(i) for f in q]

        # find atomics -> so also ldlf formulas
        # replace atomic with custom object
        # convert to sympy

        # find the list of atoms, which are "true" atoms
        # (i.e. propositional atoms) or LDLf formulas
        atomics = [s for subf in delta_formulas for s in find_atomics(subf)]

        atom2id = {v: str(k)
                   for k, v in enumerate(atomics)}  # type: Dict[PLAtomic, str]
        id2atom = {v: k
                   for k, v in atom2id.items()}  # type: Dict[str, PLAtomic]

        # build a map from formula to a "freezed" propositional Atomic Formula
        formula2atomic_formulas = {
            f: PLAtomic(atom2id[f]) if f != PLTrue()
            and f != PLFalse()  # and not isinstance(f, PLAtomic)
            else f
            for f in atomics
        }

        # the final list of Propositional Atomic Formulas,
        # one for each formula in the original macro state Q
        transformed_delta_formulas = [
            _transform_delta(f, formula2atomic_formulas)
            for f in delta_formulas
        ]

        # the empty conjunction stands for true
        if len(transformed_delta_formulas) == 0:
            conjunctions = PLTrue()
        elif len(transformed_delta_formulas) == 1:
            conjunctions = transformed_delta_formulas[0]
        else:
            conjunctions = PLAnd(transformed_delta_formulas)  # type: ignore

        # the model in this case is the smallest set of symbols
        # s.t. the conjunction of "freezed" atomic formula is true.
        # alphabet = frozenset(symbol2formula)
        # models = frozenset(conjunctions.minimal_models(alphabet))

        formula = to_sympy(conjunctions, replace=atom2id)  # type: ignore
        all_models = list(sympy.satisfiable(formula, all_models=True))
        if len(all_models) == 1 and all_models[0] == BooleanFalse():
            models = []  # type: List[Set[str]]
        elif len(all_models) == 1 and all_models[0] == {True: True}:
            models = [set()]
        else:
            models = list(
                map(lambda x: {k
                               for k, v in x.items()
                               if v is True}, all_models))

        for min_model in models:
            q_prime = frozenset({id2atom[s] for s in map(str, min_model)})
            new_macrostate.add(q_prime)

    return frozenset(new_macrostate)
Ejemplo n.º 30
0
 def _delta(self, i: PropositionalInterpretation, epsilon: bool = False):
     """Apply the delta function."""
     if epsilon:
         return PLFalse()
     else:
         return PLTrue()