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))
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))
def test_to_nnf_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.to_nnf(a), a) self.assertEqual(pl.to_nnf(Not(b)), Not(b)) self.assertEqual(pl.to_nnf(And(a, b)), And(a, b))
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
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
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")