Beispiel #1
0
 def test_is_formula_composed(self):
     a_sym = Symbol("a")
     alphabet = Alphabet({a_sym})
     a = AtomicFormula(a_sym)
     pl = PL(alphabet)
     self.assertTrue(
         pl.is_formula(
             Implies(Not(a), And(TrueFormula(), Not(FalseFormula())))))
     self.assertFalse(
         pl.is_formula(
             Implies(Not(a), And(TrueFormula(), Next(FalseFormula())))))
Beispiel #2
0
 def to_equivalent_formula(self, derived_formula: Formula):
     if isinstance(derived_formula, Or):
         return Not(And(Not(derived_formula.f1), Not(derived_formula.f2)))
     elif isinstance(derived_formula, PathExpressionAlways):
         return Not(PathExpressionEventually(derived_formula.p, Not(derived_formula.f)))
     elif isinstance(derived_formula, FalseFormula):
         return And(Not(DUMMY_ATOMIC), DUMMY_ATOMIC)
     elif isinstance(derived_formula, TrueFormula):
         return Not(FalseFormula())
     elif isinstance(derived_formula, LDLfLast):
         return PathExpressionAlways(TrueFormula(), FalseFormula())
     else:
         raise ValueError("Derived formula not recognized")
Beispiel #3
0
 def to_equivalent_formula(self, derived_formula: Formula):
     if isinstance(derived_formula, Or):
         return Not(And(Not(derived_formula.f1), Not(derived_formula.f2)))
     elif isinstance(derived_formula, Always):
         return Not(Eventually(Not(derived_formula.f)))
     elif isinstance(derived_formula, Eventually):
         return Until(TrueFormula(), derived_formula.f)
     elif isinstance(derived_formula, FalseFormula):
         return And(Not(DUMMY_ATOMIC), DUMMY_ATOMIC)
     elif isinstance(derived_formula, TrueFormula):
         return Not(FalseFormula())
     elif isinstance(derived_formula, LDLfLast):
         return Next(TrueFormula(), FalseFormula())
     else:
         raise ValueError("Derived formula not recognized")
Beispiel #4
0
    def setUp(self):
        """Set up test fixtures, if any."""
        self.a_sym = Symbol("a")
        self.b_sym = Symbol("b")
        self.c_sym = Symbol("c")
        self.alphabet = Alphabet({self.a_sym, self.b_sym, self.c_sym})

        # Propositions
        self.a = AtomicFormula(self.a_sym)
        self.b = AtomicFormula(self.b_sym)
        self.c = AtomicFormula(self.c_sym)

        self.not_a = Not(self.a)
        self.not_a_and_b = And(self.not_a, self.b)
        self.not_a_or_c = Or(self.not_a, self.c)
        self.true = TrueFormula()
        self.false = FalseFormula()

        self.symbol2truth = {
            self.a_sym: True,
            self.b_sym: False,
            self.c_sym: True
        }
        self.I = PLInterpretation(self.alphabet, self.symbol2truth)
        self.PL = PL(self.alphabet)
Beispiel #5
0
    def test_to_nnf_derived_formulas(self):
        fol = self.fol
        john = ConstantTerm.fromString("john")
        x = Variable.fromString("x")
        right_equal = Equal(x, john)
        true_ = TrueFormula()
        false_ = FalseFormula()
        or_ = Or(true_, Not(right_equal))
        implies_ = Implies(or_, false_)
        equivalence_ = Equivalence(implies_, false_)
        forall_true_ = ForAll(x, true_)
        forall_not_or_ = ForAll(x, Not(or_))
        forall_equivalence_ = ForAll(x, equivalence_)

        to_nnf_true_ = Equal(DUMMY_TERM, DUMMY_TERM)
        to_nnf_false_ = Not(Equal(DUMMY_TERM, DUMMY_TERM))
        to_nnf_or_ = Or(to_nnf_true_, Not(right_equal))
        to_nnf_not_or_ = And(Not(to_nnf_true_), right_equal)
        to_nnf_implies_ = Or(to_nnf_not_or_, to_nnf_false_)

        not_to_nnf_implies_ = And(to_nnf_or_, to_nnf_true_)
        positive_equivalence = And(to_nnf_implies_, to_nnf_false_)
        negative_equivalence = And(not_to_nnf_implies_, to_nnf_true_)
        to_nnf_equivalence_ = Or(positive_equivalence, negative_equivalence)

        self.assertEqual(fol.to_nnf(true_), to_nnf_true_)
        self.assertEqual(fol.to_nnf(false_), to_nnf_false_)
        self.assertEqual(fol.to_nnf(or_), to_nnf_or_)
        self.assertEqual(fol.to_nnf(implies_), to_nnf_implies_)
        self.assertEqual(fol.to_nnf(equivalence_), to_nnf_equivalence_)
        self.assertEqual(fol.to_nnf(forall_true_), ForAll(x, to_nnf_true_))
        self.assertEqual(fol.to_nnf(forall_not_or_), ForAll(x, to_nnf_not_or_))
        self.assertEqual(fol.to_nnf(forall_equivalence_),
                         ForAll(x, to_nnf_equivalence_))
Beispiel #6
0
    def test_expand_formula_derived_formulas(self):
        fol = self.fol
        john = ConstantTerm.fromString("john")
        x = Variable.fromString("x")
        right_equal = Equal(x, john)
        true_ = TrueFormula()
        false_ = FalseFormula()
        or_ = Or(true_, Not(right_equal))
        implies_ = Implies(or_, false_)
        equivalence_ = Equivalence(implies_, false_)
        forall_ = ForAll(x, equivalence_)

        expanded_true = Equal(DUMMY_TERM, DUMMY_TERM)
        expanded_false = Not(Equal(DUMMY_TERM, DUMMY_TERM))
        expanded_or_ = Not(And(Not(expanded_true), Not(Not(right_equal))))
        expanded_implies_ = Not(And(expanded_or_, Not(expanded_false)))

        positive_equivalence = And(expanded_implies_, expanded_false)
        negative_equivalence = And(Not(expanded_implies_), Not(expanded_false))
        expanded_equivalence_ = Not(
            And(Not(positive_equivalence), Not(negative_equivalence)))

        self.assertEqual(fol.expand_formula(true_), expanded_true)
        self.assertEqual(fol.expand_formula(false_), expanded_false)
        self.assertEqual(fol.expand_formula(or_), expanded_or_)
        self.assertEqual(fol.expand_formula(implies_), expanded_implies_)
        self.assertEqual(fol.expand_formula(equivalence_),
                         expanded_equivalence_)
        self.assertEqual(fol.expand_formula(forall_),
                         Not(Exists(x, Not(expanded_equivalence_))))
Beispiel #7
0
 def test_expand_formula_composed(self):
     a_sym = Symbol("a")
     alphabet = Alphabet({a_sym})
     a = AtomicFormula(a_sym)
     # T = Not(And(Not(DUMMY_ATOMIC), DUMMY_ATOMIC))
     # F = And(Not(DUMMY_ATOMIC), DUMMY_ATOMIC)
     T = TrueFormula()
     F = FalseFormula()
     pl = PL(alphabet)
     self.assertEqual(pl.expand_formula(And(TrueFormula(), FalseFormula())),
                      And(T, F))
     self.assertEqual(pl.expand_formula(Or(TrueFormula(), FalseFormula())),
                      Not(And(Not(T), Not(F))))
     self.assertEqual(
         pl.expand_formula(Implies(TrueFormula(), FalseFormula())),
         Not(And(Not(Not(T)), Not(F))))
     self.assertEqual(
         pl.expand_formula(Equivalence(TrueFormula(), FalseFormula())),
         Not(And(Not(And(T, F)), Not(And(Not(T), Not(F))))))
Beispiel #8
0
 def test_expand_formula_derived_formulas(self):
     a_sym = Symbol("a")
     b_sym = Symbol("b")
     alphabet = Alphabet({a_sym, b_sym})
     a = AtomicFormula(a_sym)
     b = AtomicFormula(b_sym)
     # T = Not(And(Not(DUMMY_ATOMIC), DUMMY_ATOMIC))
     # F = And(Not(DUMMY_ATOMIC), DUMMY_ATOMIC)
     T = TrueFormula()
     F = FalseFormula()
     pl = PL(alphabet)
     self.assertEqual(pl.expand_formula(TrueFormula()), T)
     self.assertEqual(pl.expand_formula(FalseFormula()), F)
     self.assertEqual(pl.expand_formula(Or(a, b)), Not(And(Not(a), Not(b))))
     self.assertEqual(pl.expand_formula(Implies(a, b)),
                      Not(And(Not(Not(a)), Not(b))))
     self.assertEqual(pl.expand_formula(Implies(b, a)),
                      Not(And(Not(Not(b)), Not(a))))
     # A === B = (A AND B) OR (NOT A AND NOT B) = NOT( NOT(A AND B) AND NOT(NOT A AND NOT B) )
     self.assertEqual(pl.expand_formula(Equivalence(a, b)),
                      Not(And(Not(And(a, b)), Not(And(Not(a), Not(b))))))
Beispiel #9
0
 def test_truth_propositional(self):
     ref = self.ref
     a = self.a
     b = self.b
     c = self.c
     self.assertTrue(ref.truth(a, self.trace_1, 0, 1))
     self.assertTrue(ref.truth(And(Not(b), And(a, c)), self.trace_1, 1, 2))
     self.assertFalse(ref.truth(And(b, And(a, c)), self.trace_1, 1, 2))
     self.assertTrue(ref.truth(TrueFormula(), self.trace_1, 0, 1))
     self.assertFalse(ref.truth(FalseFormula(), self.trace_1, 0, 1))
     self.assertFalse(ref.truth(TrueFormula(), self.trace_1, 0, 5))
     self.assertFalse(ref.truth(TrueFormula(), self.trace_1, 0, 0))
Beispiel #10
0
    def test_is_formula_derived(self):
        fol = self.fol
        john = ConstantTerm.fromString("john")
        not_a_term = ConstantTerm.fromString("NotATerm")
        x = Variable.fromString("x")
        y = Variable.fromString("y")
        right_equal = Equal(x, john)
        wrong_equal = Equal(x, not_a_term)

        self.assertTrue(fol.is_formula(TrueFormula()))
        self.assertTrue(fol.is_formula(FalseFormula()))

        self.assertTrue(fol.is_formula(Or(right_equal, right_equal)))
        self.assertFalse(fol.is_formula(Or(right_equal, wrong_equal)))

        self.assertTrue(fol.is_formula(Or(right_equal, right_equal)))
        self.assertFalse(fol.is_formula(Or(right_equal, wrong_equal)))

        self.assertTrue(fol.is_formula(Implies(right_equal, right_equal)))
        self.assertFalse(fol.is_formula(Implies(right_equal, wrong_equal)))

        self.assertTrue(fol.is_formula(Equivalence(right_equal, right_equal)))
        self.assertFalse(fol.is_formula(Equivalence(right_equal, wrong_equal)))

        self.assertTrue(
            fol.is_formula(
                ForAll(x,
                       PredicateFormula(PredicateSymbol("Person", 2), john,
                                        x))))
        self.assertFalse(
            fol.is_formula(
                ForAll(
                    x,
                    PredicateFormula(PredicateSymbol("Person", 3), john, x,
                                     john))))
        self.assertFalse(
            fol.is_formula(
                ForAll(
                    x,
                    PredicateFormula(PredicateSymbol("Person_fake", 2), john,
                                     x))))
Beispiel #11
0
 def to_equivalent_formula(self, derived_formula: Formula):
     # make lines shorter
     ef = self.to_equivalent_formula
     if isinstance(derived_formula, AtomicFormula):
         return PathExpressionEventually(derived_formula, LogicalTrue())
     elif isinstance(derived_formula, LogicalFalse):
         return Not(LogicalTrue())
     elif isinstance(derived_formula, Or):
         return Not(And(Not(derived_formula.f1), Not(derived_formula.f2)))
     elif isinstance(derived_formula, PathExpressionAlways):
         return Not(
             PathExpressionEventually(derived_formula.p,
                                      Not(derived_formula.f)))
     elif isinstance(derived_formula, Next):
         return PathExpressionEventually(
             TrueFormula(), And(derived_formula.f, Not(ef(End()))))
     elif isinstance(derived_formula, End):
         return ef(PathExpressionAlways(TrueFormula(), ef(LogicalFalse())))
     elif isinstance(derived_formula, Until):
         return PathExpressionEventually(
             PathExpressionStar(
                 PathExpressionSequence(
                     PathExpressionTest(derived_formula.f1),
                     ef(TrueFormula()))),
             And(derived_formula.f2, Not(ef(End()))))
     elif isinstance(derived_formula, FalseFormula):
         return FalseFormula()
     elif isinstance(derived_formula, TrueFormula):
         return TrueFormula()
     elif isinstance(derived_formula, LDLfLast):
         return PathExpressionEventually(ef(TrueFormula()), ef(End()))
     # propositional
     elif isinstance(derived_formula, Formula):
         pl = PL(self.alphabet)
         assert pl.is_formula(derived_formula)
         f = pl.to_nnf(derived_formula)
         return PathExpressionEventually(f, LogicalTrue())
     else:
         raise ValueError("Derived formula not recognized")
Beispiel #12
0
    def test_minimal_models(self):
        a = Symbol("a")
        b = Symbol("b")
        c = Symbol("c")
        alphabet = Alphabet({a, b, c})
        pl = PL(alphabet)

        atomic_a = AtomicFormula(a)
        atomic_b = AtomicFormula(b)
        atomic_c = AtomicFormula(c)

        self.assertEqual(
            pl.minimal_models(TrueFormula()),
            {PLInterpretation(alphabet, {
                a: False,
                b: False,
                c: False
            })})
        self.assertEqual(pl.minimal_models(FalseFormula()), set())
        self.assertEqual(
            pl.minimal_models(atomic_a),
            {PLInterpretation(alphabet, {
                a: True,
                b: False,
                c: False
            })})
        self.assertEqual(
            pl.minimal_models(Not(atomic_a)),
            {PLInterpretation(alphabet, {
                a: False,
                b: False,
                c: False
            })})
        self.assertEqual(
            pl.minimal_models(And(atomic_a, atomic_b)),
            {PLInterpretation(alphabet, {
                a: True,
                b: True,
                c: False
            })})
        self.assertEqual(pl.minimal_models(And(atomic_a, Not(atomic_a))),
                         set())
        self.assertEqual(
            pl.minimal_models(Or(atomic_a, atomic_b)), {
                PLInterpretation(alphabet, {
                    a: False,
                    b: True,
                    c: False
                }),
                PLInterpretation(alphabet, {
                    a: True,
                    b: False,
                    c: False
                })
            })
        self.assertEqual(
            pl.minimal_models(And.chain([atomic_a, atomic_b, atomic_c])),
            {PLInterpretation(alphabet, {
                a: True,
                b: True,
                c: True
            })})
Beispiel #13
0
 def delta(self, f: Formula, action: FrozenSet[Symbol], epsilon=False):
     # TODO: should return [True|False]Formula or simply True/False?
     pl, I = PL._from_set_of_propositionals(action, self.alphabet)
     if pl.is_formula(f):
         return self.delta(PathExpressionEventually(f, LogicalTrue()),
                           action, epsilon)
     elif isinstance(f, LogicalTrue):
         return TrueFormula()
     elif isinstance(f, LogicalFalse):
         return FalseFormula()
     elif isinstance(f, And):
         return And(self.delta(f.f1, action),
                    self.delta(f.f2, action, epsilon))
     elif isinstance(f, Or):
         return Or(self.delta(f.f1, action),
                   self.delta(f.f2, action, epsilon))
     elif isinstance(f, PathExpressionEventually):
         if pl.is_formula(f.p):
             if not epsilon and pl.truth(f.p, I):
                 return self._expand(f.f)
             else:
                 return FalseFormula()
         elif isinstance(f.p, PathExpressionTest):
             return And(self.delta(f.p.f, action, epsilon),
                        self.delta(f.f, action, epsilon))
         elif isinstance(f.p, PathExpressionUnion):
             return Or(
                 self.delta(PathExpressionEventually(f.p.p1, f.f), action,
                            epsilon),
                 self.delta(PathExpressionEventually(f.p.p2, f.f), action,
                            epsilon))
         elif isinstance(f.p, PathExpressionSequence):
             e2 = PathExpressionEventually(f.p.p2, f.f)
             e1 = PathExpressionEventually(f.p.p1, e2)
             return self.delta(e1, action, epsilon)
         elif isinstance(f.p, PathExpressionStar):
             o1 = self.delta(f.f, action, epsilon)
             o2 = self.delta(PathExpressionEventually(f.p.p, F(f)), action,
                             epsilon)
             return Or(o1, o2)
     elif isinstance(f, PathExpressionAlways):
         if pl.is_formula(f.p):
             if not epsilon and pl.truth(f.p, I):
                 return self._expand(f.f)
             else:
                 return TrueFormula()
         elif isinstance(f.p, PathExpressionTest):
             o1 = self.delta(self.to_nnf(Not(f.p.f)), action, epsilon)
             o2 = self.delta(f.f, action, epsilon)
             return Or(o1, o2)
         elif isinstance(f.p, PathExpressionUnion):
             return And(
                 self.delta(PathExpressionAlways(f.p.p1, f.f), action,
                            epsilon),
                 self.delta(PathExpressionAlways(f.p.p2, f.f), action,
                            epsilon))
         elif isinstance(f.p, PathExpressionSequence):
             return self.delta(
                 PathExpressionAlways(f.p.p1,
                                      PathExpressionAlways(f.p.p2, f.f)),
                 action, epsilon)
         elif isinstance(f.p, PathExpressionStar):
             a1 = self.delta(f.f, action, epsilon)
             a2 = self.delta(PathExpressionAlways(f.p.p, T(f)), action,
                             epsilon)
             return And(a1, a2)
     elif isinstance(f, F):
         return FalseFormula()
     elif isinstance(f, T):
         return TrueFormula()
     else:
         raise ValueError
Beispiel #14
0
    def to_nfa(self, f: Formula):
        # TODO: optimize!!!
        assert self.is_formula(f)
        nnf_f = self.to_nnf(f)

        alphabet = powerset(self.alphabet.symbols)
        initial_states = {frozenset([nnf_f])}
        final_states = {frozenset()}
        delta = set()

        pl, I = PL._from_set_of_propositionals(set(), Alphabet(set()))
        d = self.delta(nnf_f, frozenset(), epsilon=True)
        if pl.truth(d, I):
            final_states.add(frozenset([nnf_f]))

        states = {frozenset(), frozenset([nnf_f])}

        states_changed, delta_changed = True, True
        while states_changed or delta_changed:

            states_changed, delta_changed = False, False
            for actions_set in alphabet:
                states_list = list(states)
                for q in states_list:

                    delta_formulas = [
                        self.delta(subf, actions_set) for subf in q
                    ]
                    atomics = [
                        s for subf in delta_formulas
                        for s in PL.find_atomics(subf)
                    ]

                    symbol2formula = {
                        Symbol(str(f)): f
                        for f in atomics
                        if f != TrueFormula() and f != FalseFormula()
                    }
                    formula2atomic_formulas = {
                        f: AtomicFormula.fromName(str(f))
                        if f != TrueFormula() and f != FalseFormula() else f
                        for f in atomics
                    }
                    transformed_delta_formulas = [
                        self._tranform_delta(f, formula2atomic_formulas)
                        for f in delta_formulas
                    ]
                    conjunctions = And.chain(transformed_delta_formulas)

                    models = frozenset(
                        PL(Alphabet(
                            set(symbol2formula))).minimal_models(conjunctions))
                    if len(models) == 0:
                        continue
                    for min_model in models:
                        q_prime = frozenset({
                            symbol2formula[s]
                            for s in min_model.symbol2truth
                            if min_model.symbol2truth[s]
                        })

                        len_before = len(states)
                        states.add(q_prime)
                        if len(states) == len_before + 1:
                            states_list.append(q_prime)
                            states_changed = True

                        len_before = len(delta)
                        delta.add((q, actions_set, q_prime))
                        if len(delta) == len_before + 1:
                            delta_changed = True

                        # check if q_prime should be added as final state
                        if len(q_prime) == 0:
                            final_states.add(q_prime)
                        else:
                            q_prime_delta_conjunction = And.chain([
                                self.delta(subf, frozenset(), epsilon=True)
                                for subf in q_prime
                            ])
                            pl, I = PL._from_set_of_propositionals(
                                set(), Alphabet(set()))
                            if pl.truth(q_prime_delta_conjunction, I):
                                final_states.add(q_prime)

        return {
            "alphabet": alphabet,
            "states": frozenset(states),
            "initial_states": frozenset(initial_states),
            "transitions": delta,
            "accepting_states": frozenset(final_states)
        }