Beispiel #1
0
    def to_nnf(self, f: Formula):
        assert self.is_formula(f)
        formula = self.expand_formula(f)

        if isinstance(formula, PredicateFormula) or isinstance(formula, Equal):
            return formula
        elif isinstance(formula, And):
            return And(self.to_nnf(formula.f1), self.to_nnf(formula.f2))
        if isinstance(formula, Exists):
            return Exists(formula.v, self.to_nnf(formula.f))
        if isinstance(formula, Not):
            subformula = formula.f
            if isinstance(subformula, Not):
                return self.to_nnf(subformula.f)
            elif isinstance(subformula, And):
                return Or(self.to_nnf(Not(subformula.f1)),
                          self.to_nnf((Not(subformula.f2))))
            elif isinstance(subformula, Exists):
                return ForAll(subformula.v, self.to_nnf(Not(subformula.f)))
            elif isinstance(subformula, PredicateFormula) or isinstance(
                    subformula, Equal):
                return formula
            else:
                raise ValueError
        else:
            raise ValueError
Beispiel #2
0
 def to_nnf(self, f: Formula):
     # assert self.is_formula(f)
     # formula = self.expand_formula(f)
     formula = f
     if isinstance(formula, AtomicFormula) or isinstance(
             formula, TrueFormula) or isinstance(formula, FalseFormula):
         return formula
     elif isinstance(formula, And) or isinstance(formula, Or):
         return type(formula)(self.to_nnf(formula.f1),
                              self.to_nnf(formula.f2))
     elif type(formula) in self.derived_formulas:
         return self.to_nnf(self.derived_formulas[type(formula)](formula))
     elif isinstance(formula, Not):
         subformula = formula.f
         if isinstance(subformula, Not):
             return self.to_nnf(subformula.f)
         elif isinstance(subformula, And):
             return Or(self.to_nnf(Not(subformula.f1)),
                       self.to_nnf((Not(subformula.f2))))
         elif isinstance(subformula, Or):
             return And(self.to_nnf(Not(subformula.f1)),
                        self.to_nnf((Not(subformula.f2))))
         elif isinstance(subformula, AtomicFormula) or isinstance(
                 formula, TrueFormula) or isinstance(formula, FalseFormula):
             return formula
         elif type(subformula) in self.derived_formulas:
             return self.to_nnf(
                 Not(self.derived_formulas[type(subformula)](subformula)))
         else:
             raise ValueError
     else:
         raise ValueError
Beispiel #3
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 #4
0
    def test_is_formula_not(self):
        fol = self.fol
        john = ConstantTerm.fromString("john")
        paul = ConstantTerm.fromString("paul")
        not_a_term = ConstantTerm.fromString("NotATerm")
        right_equal = Equal(john, paul)
        wrong_equal = Equal(john, not_a_term)

        self.assertTrue(fol.is_formula(Not(right_equal)))
        self.assertFalse(fol.is_formula(Not(wrong_equal)))

        self.assertTrue(
            fol.is_formula(
                Not(PredicateFormula(PredicateSymbol("Person", 2), john,
                                     paul))))
        self.assertFalse(
            fol.is_formula(
                Not(
                    PredicateFormula(PredicateSymbol("Person", 3), john, paul,
                                     john))))
        self.assertFalse(
            fol.is_formula(
                Not(
                    PredicateFormula(PredicateSymbol("Person_fake", 2), john,
                                     paul))))
Beispiel #5
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))
Beispiel #6
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))
Beispiel #7
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))
Beispiel #8
0
 def test_truth_union(self):
     ref = self.ref
     a = self.a
     b = self.b
     c = self.c
     self.assertTrue(
         ref.truth(PathExpressionUnion(a, b), self.trace_1, 0, 1))
     self.assertTrue(
         ref.truth(PathExpressionUnion(a, c), self.trace_1, 4, 5))
     self.assertFalse(
         ref.truth(PathExpressionUnion(Not(b), Not(c)), self.trace_1, 4, 5))
Beispiel #9
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 #10
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 #11
0
 def _expand_formula(self, f: Formula):
     if isinstance(f, AtomicFormula):
         return f
     elif isinstance(f, And):
         return And(self.expand_formula(f.f1), self.expand_formula(f.f2))
     elif isinstance(f, Not):
         return Not(self.expand_formula(f.f))
     else:
         raise ValueError("Formula to expand not recognized")
Beispiel #12
0
 def _not_to_nnf(self, not_formula: Not):
     subformula = not_formula.f
     if isinstance(subformula, AtomicFormula):
         return not_formula
     if isinstance(subformula, Not):
         # skip two consecutive Not
         new_formula = subformula.f
         return self.to_nnf(new_formula)
     elif isinstance(subformula, And):
         return Or(self.to_nnf(Not(subformula.f1)), self.to_nnf(Not(subformula.f2)))
     elif isinstance(subformula, Or):
         return And(self.to_nnf(Not(subformula.f1)), self.to_nnf(Not(subformula.f2)))
     elif isinstance(subformula, PathExpressionEventually):
         return PathExpressionAlways(self.to_nnf_path(subformula.p), self.to_nnf(Not(subformula.f)))
     elif isinstance(subformula, PathExpressionAlways):
         return PathExpressionEventually(self.to_nnf_path(subformula.p), self.to_nnf(Not(subformula.f)))
     else:
         raise ValueError
Beispiel #13
0
 def _tranform_delta(self, f: Formula, formula2AtomicFormula):
     if isinstance(f, Not):
         return Not(self._tranform_delta(f, formula2AtomicFormula))
     elif isinstance(f, And) or isinstance(f, Or):
         return type(f)(self._tranform_delta(f.f1, formula2AtomicFormula),
                        self._tranform_delta(f.f2, formula2AtomicFormula))
     elif isinstance(f, TrueFormula) or isinstance(f, FalseFormula):
         return f
     else:
         return formula2AtomicFormula[f]
Beispiel #14
0
 def _expand_formula(self, f: Formula):
     if isinstance(f, PredicateFormula) or isinstance(f, Equal):
         return f
     elif isinstance(f, And):
         return And(self.expand_formula(f.f1), self.expand_formula(f.f2))
     elif isinstance(f, Not):
         return Not(self.expand_formula(f.f))
     elif isinstance(f, Exists):
         return Exists(f.v, self.expand_formula(f.f))
     else:
         raise ValueError("Not valid Formula to expand.")
Beispiel #15
0
 def _expand_formula(self, f: Formula):
     if isinstance(f, AtomicFormula):
         return f
     elif isinstance(f, And):
         return And(self.expand_formula(f.f1), self.expand_formula(f.f2))
     elif isinstance(f, Not):
         return Not(self.expand_formula(f.f))
     elif isinstance(f, PathExpressionEventually):
         return PathExpressionEventually(f.p, self.expand_formula(f.f))
     else:
         raise ValueError("Not valid Formula to expand")
Beispiel #16
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 #17
0
    def _build_automata(self):
        rows = self.row_symbols
        atoms = [AtomicFormula(r) for r in rows]
        alphabet = Alphabet(set(rows))
        ldlf = LDLf_EmptyTraces(alphabet)
        f = PathExpressionEventually(
            PathExpressionSequence.chain([
                PathExpressionStar(
                    And.chain([Not(atoms[0]),
                               Not(atoms[1]),
                               Not(atoms[2])])),
                PathExpressionStar(
                    And.chain([atoms[0],
                               Not(atoms[1]),
                               Not(atoms[2])])),
                # Not(atoms[3]), Not(atoms[4]), Not(atoms[5])]),
                PathExpressionStar(
                    And.chain([atoms[0], atoms[1],
                               Not(atoms[2])])),
                # Not(atoms[3]), Not(atoms[4]), Not(atoms[5])]),
                # And.chain([atoms[0],      atoms[1],      atoms[2]]),  # Not(atoms[3]), Not(atoms[4]), Not(atoms[5])]),
                # And.chain([atoms[0],     atoms[1],      atoms[2],      atoms[3],  Not(atoms[4]), Not(atoms[5])]),
                # And.chain([atoms[0],     atoms[1],      atoms[2],      atoms[3],      atoms[4],  Not(atoms[5])]),
                # And.chain([atoms[0],     atoms[1],      atoms[2],      atoms[3],      atoms[4],      atoms[5] ])
            ]),
            And.chain([atoms[0], atoms[1], atoms[2]]))
        nfa = ldlf.to_nfa(f)
        dfa = _to_pythomata_dfa(nfa)

        return dfa
Beispiel #18
0
    def test_to_nnf_allowed_formulas(self):
        fol = self.fol
        john = ConstantTerm.fromString("john")
        x = Variable.fromString("x")
        right_equal = Equal(x, john)
        not_ = Not(right_equal)
        and_ = And(right_equal, not_)
        exists_ = Exists(x, right_equal)

        self.assertEqual(fol.to_nnf(right_equal), right_equal)
        self.assertEqual(fol.to_nnf(not_), not_)
        self.assertEqual(fol.to_nnf(and_), and_)
        self.assertEqual(fol.to_nnf(exists_), exists_)
Beispiel #19
0
 def _expand_formula(self, f: Formula):
     if isinstance(f, AtomicFormula):
         return f
     elif isinstance(f, And):
         return And(self.expand_formula(f.f1), self.expand_formula(f.f2))
     elif isinstance(f, Not):
         return Not(self.expand_formula(f.f))
     elif isinstance(f, Until):
         return Until(self.expand_formula(f.f1), self.expand_formula(f.f2))
     elif isinstance(f, Next):
         return Next(self.expand_formula(f.f))
     else:
         raise ValueError("Not valid Formula to expand")
Beispiel #20
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 #21
0
    def test_to_nnf(self):
        f1 = Not(
            PathExpressionEventually(
                PathExpressionSequence(PathExpressionTest(Not(self.a_and_b)),
                                       PathExpressionStar(TrueFormula())),
                self.abc))
        nnf_f1 = PathExpressionAlways(
            PathExpressionSequence(
                PathExpressionTest(Or(Not(self.a), Not(self.b))),
                # PathExpressionStar(Or(DUMMY_ATOMIC, Not(DUMMY_ATOMIC)))
                PathExpressionStar(TrueFormula())),
            Or(Not(self.a), Or(Not(self.b), Not(self.c))))

        self.assertEqual(self.ldlf.to_nnf(f1), nnf_f1)
Beispiel #22
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 #23
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 #24
0
    def test_truth(self):
        self.assertFalse(self.ldlf.truth(self.not_a, self.trace_1, 0))
        self.assertTrue(self.ldlf.truth(self.not_a, self.trace_1, 4))
        self.assertTrue(self.ldlf.truth(self.a_and_b, self.trace_1, 0))
        self.assertFalse(self.ldlf.truth(self.a_and_b, self.trace_1, 1))
        self.assertTrue(self.ldlf.truth(self.a_or_b, self.trace_1, 1))
        self.assertTrue(
            self.ldlf.truth(Not(And(self.b, self.c)), self.trace_1, 0))

        self.assertTrue(
            self.ldlf.truth(self.eventually_seq_a_and_b__a_and_c__not_c,
                            self.trace_1, 0))
        self.assertFalse(
            self.ldlf.truth(self.eventually_seq_a_and_b__a_and_c__not_c,
                            self.trace_1, 1))
        self.assertTrue(
            self.ldlf.truth(self.eventually_propositional_a_and_b__a_and_c,
                            self.trace_1, 0))
        self.assertFalse(
            self.ldlf.truth(self.eventually_test_a__c, self.trace_1, 0))
        self.assertTrue(
            self.ldlf.truth(self.eventually_test_a__b, self.trace_1, 0))
        self.assertTrue(
            self.ldlf.truth(self.eventually_seq_a_and_b__a_and_c__not_c,
                            self.trace_1, 0))
        self.assertFalse(
            self.ldlf.truth(self.eventually_seq_a_and_b__a_and_c__c,
                            self.trace_1, 0))
        self.assertTrue(self.ldlf.truth(self.next_a_and_c, self.trace_1, 0))
        self.assertTrue(self.ldlf.truth(self.liveness_b_and_c, self.trace_1,
                                        0))
        self.assertFalse(self.ldlf.truth(self.liveness_abc, self.trace_1, 0))

        self.assertFalse(self.ldlf.truth(self.always_true__a, self.trace_1, 0))
        self.assertTrue(
            self.ldlf.truth(self.always_true__a,
                            self.trace_1.segment(0,
                                                 self.trace_1.length() - 1),
                            0))
        self.assertTrue(
            self.ldlf.truth(self.always_true__b_or_c, self.trace_1, 0))
Beispiel #25
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 #26
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 #27
0
def _falseFormula_to_equivalent_formula(*args) -> Formula:
    return And(DUMMY_ATOMIC, Not(DUMMY_ATOMIC))
Beispiel #28
0
def _or_to_and(f: Or) -> Formula:
    return Not(And(Not(f.f1), Not(f.f2)))
Beispiel #29
0
def _implies_to_or(f: Implies) -> Formula:
    equivalent_formula = Or(Not(f.f1), f.f2)
    return _or_to_and(equivalent_formula)
Beispiel #30
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))))))