示例#1
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)
示例#2
0
    def test_expand_formula_error(self):
        a_sym = Symbol("a")
        alphabet = Alphabet({a_sym})
        a = Next(AtomicFormula(a_sym))
        pl = PL(alphabet)

        with self.assertRaises(ValueError) as ve:
            pl.expand_formula(a)
示例#3
0
 def test_to_nnf_allowed_formulas_not_normalized(self):
     a_sym = Symbol("a")
     b_sym = Symbol("b")
     alphabet = Alphabet({a_sym, b_sym})
     a = AtomicFormula(a_sym)
     b = AtomicFormula(b_sym)
     pl = PL(alphabet)
     self.assertEqual(pl.to_nnf(Not(Not(b))), b)
     self.assertEqual(pl.to_nnf(Not(And(a, Not(b)))), Or(Not(a), b))
示例#4
0
 def test_to_nnf_derived_formula(self):
     a_sym = Symbol("a")
     b_sym = Symbol("b")
     alphabet = Alphabet({a_sym, b_sym})
     a = AtomicFormula(a_sym)
     b = AtomicFormula(b_sym)
     pl = PL(alphabet)
     self.assertEqual(pl.to_nnf(Not(Or(b, Not(a)))), And(Not(b), a))
     self.assertEqual(pl.to_nnf(Not(Implies(b, Not(a)))), And(b, a))
示例#5
0
 def expand_formula(self, f: Formula):
     """Manage the case when we have a propositional formula."""
     # Check first if it is a propositional
     pl = PL(self.alphabet)
     if pl.is_formula(f):
         return super().expand_formula(
             PathExpressionEventually(f, LogicalTrue()))
     else:
         return super().expand_formula(f)
示例#6
0
 def test_expand_formula_allowed_formulas(self):
     a_sym = Symbol("a")
     b_sym = Symbol("b")
     alphabet = Alphabet({a_sym, b_sym})
     a = AtomicFormula(a_sym)
     b = AtomicFormula(b_sym)
     pl = PL(alphabet)
     self.assertEqual(pl.expand_formula(a), a)
     self.assertEqual(pl.expand_formula(Not(b)), Not(b))
     self.assertEqual(pl.expand_formula(And(a, b)), And(a, b))
示例#7
0
 def _is_formula(self, f: Formula):
     """Check if a formula is legal in the current formal system"""
     if isinstance(f, PathExpressionUnion):
         return self.is_formula(f.p1) and self.is_formula(f.p2)
     elif isinstance(f, PathExpressionSequence):
         return self._is_formula(f.p1) and self._is_formula(f.p2)
     elif isinstance(f, PathExpressionStar):
         return self._is_formula(f.p)
     else:
         pl = PL(self.alphabet)
         return pl.is_formula(f)
示例#8
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())))))
示例#9
0
 def _is_path(self, p: PathExpression):
     # PathExpression
     if isinstance(p, PathExpressionUnion) or isinstance(p, PathExpressionSequence):
         return self._is_path(p.p1) and self._is_path(p.p2)
     elif isinstance(p, PathExpressionTest):
         return self.is_formula(p.f)
     elif isinstance(p, PathExpressionStar):
         return self._is_path(p.p)
     elif isinstance(p, Formula):
         pl = PL(self.alphabet)
         return pl.is_formula(p)
     else:
         raise ValueError("Argument not a valid Path")
示例#10
0
 def to_nnf(self, f: Formula):
     if isinstance(f, PathExpressionUnion):
         return PathExpressionUnion(self.to_nnf(f.p1), self.to_nnf(f.p2))
     elif isinstance(f, PathExpressionSequence):
         return PathExpressionSequence(self.to_nnf(f.p1), self.to_nnf(f.p2))
     elif isinstance(f, PathExpressionStar):
         return PathExpressionStar(self.to_nnf(f.p))
     elif isinstance(f, Formula):
         pl = PL(self.alphabet)
         assert pl.is_formula(f)
         return f
     else:
         raise ValueError
示例#11
0
 def _expand_path(self, p: PathExpression) -> PathExpression:
     if isinstance(p, PathExpressionUnion) or isinstance(
             p, PathExpressionSequence):
         return type(p)(self._expand_path(p.p1), self._expand_path(p.p2))
     elif isinstance(p, PathExpressionTest):
         return PathExpressionTest(self.expand_formula(p.f))
     elif isinstance(p, PathExpressionStar):
         return PathExpressionStar(self._expand_path(p.p))
     elif isinstance(p, Formula):
         pl = PL(self.alphabet)
         return pl.expand_formula(p)
     else:
         raise ValueError
示例#12
0
 def to_nnf_path(self, path: PathExpression):
     if isinstance(path, PathExpressionTest):
         return PathExpressionTest(self.to_nnf(path.f))
     elif isinstance(path, PathExpressionUnion):
         return PathExpressionUnion(self.to_nnf_path(path.p1), self.to_nnf_path(path.p2))
     elif isinstance(path, PathExpressionSequence):
         return PathExpressionSequence(self.to_nnf_path(path.p1), self.to_nnf_path(path.p2))
     elif isinstance(path, PathExpressionStar):
         return PathExpressionStar(self.to_nnf_path(path.p))
     elif isinstance(path, Formula):
         pl = PL(self.alphabet)
         assert pl.is_formula(path)
         return pl.to_nnf(path)
     else:
         raise ValueError
示例#13
0
 def _is_formula(self, f: Formula):
     """Check if a formula is legal in the current formal system"""
     # Check first if it is a propositional
     pl = PL(self.alphabet)
     if pl.is_formula(f):
         return self.is_formula(PathExpressionEventually(f, LogicalTrue()))
     elif isinstance(f, LogicalTrue):
         return True
     elif isinstance(f, Not):
         return self.is_formula(f.f)
     elif isinstance(f, And):
         return self.is_formula(f.f1) and self.is_formula(f.f2)
     elif isinstance(f, PathExpressionEventually):
         return self._is_path(f.p) and self.is_formula(f.f)
     else:
         return False
示例#14
0
 def to_nnf(self, f: Formula) -> Formula:
     formula = self.expand_formula(f)
     pl = PL(self.alphabet)
     if pl.is_formula(formula):
         return pl.to_nnf(formula)
     elif isinstance(formula, LogicalTrue):
         return formula
     elif isinstance(formula, And):
         return And(self.to_nnf(formula.f1), self.to_nnf(formula.f2))
     elif isinstance(formula, PathExpressionFormula):
         return type(formula)(self.to_nnf_path(formula.p),
                              self.to_nnf(formula.f))
     elif isinstance(formula, Not):
         return self._not_to_nnf(formula)
     else:
         raise ValueError
示例#15
0
    def _truth(self, f: Formula, trace: FiniteTrace, position: int):
        assert trace.alphabet == self.alphabet
        truth = self._truth

        pl = PL(self.alphabet)
        if pl.is_formula(f):
            return self.truth(PathExpressionEventually(f, LogicalTrue()),
                              trace, position)
        elif isinstance(f, LogicalTrue):
            return True
        elif isinstance(f, Not):
            return not self.truth(f.f, trace, position)
        elif isinstance(f, And):
            return self.truth(f.f1, trace, position) and self.truth(
                f.f2, trace, position)
        elif isinstance(f, PathExpressionEventually):
            path = f.p
            assert self._is_path(path)
            if isinstance(path, PathExpressionTest):
                return truth(path.f, trace, position) and truth(
                    f.f, trace, position)
            elif isinstance(path, PathExpressionUnion):
                return truth(PathExpressionEventually(path.p1, f.f), trace,
                             position) or truth(
                                 PathExpressionEventually(path.p2, f.f), trace,
                                 position)
            elif isinstance(path, PathExpressionSequence):
                return truth(
                    PathExpressionEventually(
                        path.p1, PathExpressionEventually(path.p2, f.f)),
                    trace, position)
            elif isinstance(path, PathExpressionStar):
                return truth(f.f, trace,
                             position) or (position < trace.last() and truth(
                                 PathExpressionEventually(
                                     path.p, PathExpressionEventually(
                                         path, f.f)), trace, position)
                                           and not self._is_testonly(path))
            # path should be a Propositional Formula
            else:
                pl, I = PL._from_set_of_propositionals(trace.get(position),
                                                       trace.alphabet)
                return position < trace.length() and pl.truth(
                    path, I) and truth(f.f, trace, position + 1)
        else:
            raise ValueError("Argument not a valid Formula")
示例#16
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))))))
示例#17
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))))))
示例#18
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")
示例#19
0
 def test_is_formula_error(self):
     a_sym = Symbol("a")
     alphabet = Alphabet({a_sym})
     a = Next(AtomicFormula(a_sym))
     pl = PL(alphabet)
     self.assertFalse(pl.is_formula(a))
示例#20
0
 def test_is_formula_atomic(self):
     a_sym = Symbol("a")
     alphabet = Alphabet({a_sym})
     a = AtomicFormula(a_sym)
     pl = PL(alphabet)
     self.assertTrue(pl.is_formula(a))
示例#21
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
            })})
示例#22
0
 def __init__(self, alphabet: Alphabet):
     super().__init__(alphabet)
     self.pl = PL(self.alphabet)
示例#23
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)
        }