Skip to content

Commit 584cbd9

Browse files
authored
Merge pull request #6 from DigitalFormalLogic/tests
Bugfix / implement tests for formulas and grammars
2 parents 7b19700 + eb922ab commit 584cbd9

5 files changed

Lines changed: 224 additions & 9 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pip install mathesis
9595

9696
## Roadmap
9797

98-
- [ ] Add tests
98+
- [ ] Add tests (WIP)
9999
- [ ] Hilbert systems
100100
- [x] Natural deduction
101101
- [ ] Boolean algebra

‎mathesis/forms.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def free_terms(self):
4646
return self.terms
4747

4848
def replace_term(self, replaced_term, replacing_term):
49-
fml = self
49+
fml = self.clone()
5050
fml.terms = [
5151
replacing_term if term == replaced_term else term for term in self.terms
5252
]
@@ -132,7 +132,7 @@ def free_terms(self):
132132
return self.sub.free_terms
133133

134134
def replace_term(self, replaced_term, replacing_term):
135-
fml = self
135+
fml = self.clone()
136136
fml.sub = self.sub.replace_term(replaced_term, replacing_term)
137137
return fml
138138

@@ -187,9 +187,9 @@ def free_terms(self):
187187

188188
def replace_term(self, replaced_term, replacing_term):
189189
# fml = copy(self)
190-
fml = self
190+
fml = self.clone()
191191
subs = []
192-
for subfml in self.subs:
192+
for subfml in deepcopy(self.subs):
193193
subs.append(subfml.replace_term(replaced_term, replacing_term))
194194
fml.subs = subs
195195
return fml
@@ -205,7 +205,7 @@ def latex(self):
205205
def __str__(self) -> str:
206206
# print(self.subs)
207207
# return f"{self.connective}".join(map(lambda x: f"({x})", self.subs))
208-
return f"{self.connective}".join(
208+
return f" {self.connective} ".join(
209209
map(
210210
lambda x: f"({x})" if isinstance(x, Binary) else f"{x}",
211211
self.subs,

‎mathesis/semantics/truth_table/base.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from itertools import product
55

66
from anytree import NodeMixin, PostOrderIter
7-
from prettytable import PLAIN_COLUMNS, PrettyTable
7+
from prettytable import TableStyle, PrettyTable
88

99
from mathesis import forms
1010

@@ -47,7 +47,7 @@ def to_table(self):
4747

4848
return table
4949

50-
def to_string(self, style=PLAIN_COLUMNS):
50+
def to_string(self, style=TableStyle.PLAIN_COLUMNS):
5151
table = self.to_table()
5252
table.set_style(style)
5353
return str(table)
@@ -405,7 +405,7 @@ def to_table(self):
405405

406406
return table
407407

408-
def to_string(self, style=PLAIN_COLUMNS):
408+
def to_string(self, style=TableStyle.PLAIN_COLUMNS):
409409
table = self.to_table()
410410
table.set_style(style)
411411
return str(table)

‎tests/test_forms.py‎

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from mathesis.forms import (
2+
Formula,
3+
Atom,
4+
Top,
5+
Bottom,
6+
Negation,
7+
Disjunction,
8+
Conjunction,
9+
Conditional,
10+
Universal,
11+
Particular
12+
)
13+
14+
15+
# ⊤ ∨ (¬Q ∨ R)
16+
propositional_formula_1 = Disjunction(
17+
Top(),
18+
Disjunction(
19+
Negation(Atom("Q")),
20+
Atom("R")
21+
)
22+
)
23+
24+
# (P ∧ ¬P) → ⊥
25+
propositional_formula_2 = Conditional(
26+
Conjunction(
27+
Atom("P"),
28+
Negation(Atom("P"))
29+
),
30+
Bottom()
31+
)
32+
33+
# ∀x(P(x) → (Q(x) ∨ R(x)))
34+
quantified_formula_1 = Universal(
35+
"x",
36+
Conditional(
37+
Atom("P", terms=["x"]),
38+
Disjunction(
39+
Atom("Q", terms=["x"]),
40+
Atom("R", terms=["x"])
41+
)
42+
)
43+
)
44+
45+
# ∃y(¬Q(y) ∧ ¬R(a, b, y))
46+
quantified_formula_2 = Particular(
47+
"y",
48+
Conjunction(
49+
Negation(Atom("Q", terms=["y"])),
50+
Negation(Atom("R", terms=["a", "b", "y"]))
51+
)
52+
)
53+
54+
55+
def test_repr():
56+
assert repr(propositional_formula_1) == "Disj[Top, Disj[Neg[Atom[Q]], Atom[R]]]"
57+
assert repr(propositional_formula_2) == "Cond[Conj[Atom[P], Neg[Atom[P]]], Bottom]"
58+
assert repr(quantified_formula_1) == "Forall<x>[Cond[Atom[P(x)], Disj[Atom[Q(x)], Atom[R(x)]]]]"
59+
assert repr(quantified_formula_2) == "Exists<y>[Conj[Neg[Atom[Q(y)]], Neg[Atom[R(a, b, y)]]]]"
60+
61+
62+
def test_str():
63+
assert str(propositional_formula_1) == "⊤ ∨ (¬Q ∨ R)"
64+
assert str(propositional_formula_2) == "(P ∧ ¬P) → ⊥"
65+
assert str(quantified_formula_1) == "∀x(P(x) → (Q(x) ∨ R(x)))"
66+
assert str(quantified_formula_2) == "∃y(¬Q(y) ∧ ¬R(a, b, y))"
67+
68+
69+
def test_latex():
70+
assert propositional_formula_1.latex() == r"\top \lor (\neg Q \lor R)"
71+
assert propositional_formula_2.latex() == r"(P \land \neg P) \to \bot"
72+
assert quantified_formula_1.latex() == r"\forall x (P(x) \to (Q(x) \lor R(x)))"
73+
assert quantified_formula_2.latex() == r"\exists y (\neg Q(y) \land \neg R(a, b, y))"
74+
75+
76+
def test_atoms():
77+
assert propositional_formula_1.atoms == {
78+
"Q": [Atom("Q")],
79+
"R": [Atom("R")]
80+
}
81+
assert propositional_formula_2.atoms == {
82+
"P": [Atom("P"), Atom("P")]
83+
}
84+
assert quantified_formula_1.atoms == {
85+
"P(x)": [Atom("P", terms=["x"])],
86+
"Q(x)": [Atom("Q", terms=["x"])],
87+
"R(x)": [Atom("R", terms=["x"])]
88+
}
89+
assert quantified_formula_2.atoms == {
90+
"Q(y)": [Atom("Q", terms=["y"])],
91+
"R(a, b, y)": [Atom("R", terms=["a", "b", "y"])]
92+
}
93+
94+
95+
def test_atom_symbols():
96+
assert propositional_formula_1.atom_symbols == ["Q", "R"]
97+
assert propositional_formula_2.atom_symbols == ["P"]
98+
assert quantified_formula_1.atom_symbols == ["P(x)", "Q(x)", "R(x)"]
99+
assert quantified_formula_2.atom_symbols == ["Q(y)", "R(a, b, y)"]
100+
101+
102+
def test_equality():
103+
assert propositional_formula_1 == propositional_formula_1
104+
assert propositional_formula_2 != propositional_formula_1
105+
assert propositional_formula_2 != quantified_formula_1
106+
assert quantified_formula_1 == quantified_formula_1
107+
assert quantified_formula_2 == quantified_formula_2
108+
assert quantified_formula_1 != quantified_formula_2
109+
110+
111+
def test_free_terms():
112+
assert propositional_formula_1.free_terms == []
113+
assert propositional_formula_2.free_terms == []
114+
assert quantified_formula_1.free_terms == []
115+
assert quantified_formula_2.free_terms == ["a", "b"]
116+
117+
118+
def test_replace_term():
119+
assert propositional_formula_1.replace_term("Q", "R") == propositional_formula_1
120+
assert quantified_formula_1.replace_term("x", "y") == Conditional(
121+
Atom("P", terms=["y"]),
122+
Disjunction(
123+
Atom("Q", terms=["y"]),
124+
Atom("R", terms=["y"])
125+
)
126+
)
127+
assert quantified_formula_2.replace_term("a", "b") == Conjunction(
128+
Negation(Atom("Q", terms=["y"])),
129+
Negation(Atom("R", terms=["b", "b", "y"]))
130+
)

‎tests/test_grammars.py‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from mathesis.grammars import (
2+
BasicPropositionalGrammar,
3+
BasicGrammar
4+
)
5+
from mathesis.forms import (
6+
Atom,
7+
Top,
8+
Bottom,
9+
Negation,
10+
Conjunction,
11+
Disjunction,
12+
Conditional,
13+
Universal,
14+
Particular
15+
)
16+
17+
18+
def test_propositional_grammar():
19+
grammar = BasicPropositionalGrammar()
20+
assert grammar.parse("⊥ ∨ (B → C)") == Disjunction(
21+
Bottom(),
22+
Conditional(
23+
Atom("B"),
24+
Atom("C")
25+
)
26+
)
27+
assert grammar.parse("⊤ ∧ (P_1 ∧ ¬P_2)") == Conjunction(
28+
Top(),
29+
Conjunction(
30+
Atom("P_1"),
31+
Negation(Atom("P_2"))
32+
)
33+
)
34+
35+
# Test for the order of precedence of operators
36+
assert grammar.parse("P ∨ Q ∧ ¬R → T") == Conditional(
37+
Disjunction(
38+
Atom("P"),
39+
Conjunction(
40+
Atom("Q"),
41+
Negation(Atom("R"))
42+
)
43+
),
44+
Atom("T")
45+
)
46+
47+
# Test for symbol customization
48+
grammar = BasicPropositionalGrammar(
49+
symbols={"conditional": "->"}
50+
)
51+
assert grammar.parse("A -> B") == Conditional(Atom("A"), Atom("B"))
52+
53+
54+
def test_first_order_grammar():
55+
grammar = BasicGrammar()
56+
assert grammar.parse("∀x((P(x) ∧ Q(x)) → R(x, x))") == Universal(
57+
"x",
58+
Conditional(
59+
Conjunction(
60+
Atom("P", terms=["x"]),
61+
Atom("Q", terms=["x"])
62+
),
63+
Atom("R", terms=["x", "x"])
64+
)
65+
)
66+
67+
assert grammar.parse("∃y∀x(P123(x, y) ∨ P123(y, x))") == Particular(
68+
"y",
69+
Universal(
70+
"x",
71+
Disjunction(
72+
Atom("P123", terms=["x", "y"]),
73+
Atom("P123", terms=["y", "x"])
74+
)
75+
)
76+
)
77+
78+
# Test with nullary predicates (propositions)
79+
assert grammar.parse("⊤ ∨ (A → B)") == Disjunction(
80+
Top(),
81+
Conditional(
82+
Atom("A"),
83+
Atom("B")
84+
)
85+
)

0 commit comments

Comments
 (0)