Algorithm for restoring parentheses in sentential logic sentences to turn them into well-formed formulas (WFFs)
Key concepts/tech used: recursion, combinatorics, python, mathematical modeling
Under the guidance of Dr. Jesse Fitts
Meaningful logical sentences are called well-formed formulas (WFFs). The definition of a WFF is recursive:
WFF | Not WFF |
---|---|
$A$ | $AB$ |
$(A\lor B)$ | $A( \lor B)$ |
$(A\lor B) \rightarrow (\lnot C)$ | $A( \lor \land \lnot B )$ |
While there are infinite ways to add parentheses to WFFs for them to remain WFFs, there are finite ways to restore parentheses to sentences to turn them into WFFs. The number of ways to restore parenthesis is a function of the number of operators within the sentence being restored. The following is demonstrated below:
Connectives | Ways of Restoring Parenths |
Demo |
---|---|---|
0 | 1 | $(A)$ |
1 | 1 | $(A \lor B)$ |
2 | 2 | $(A \lor B) \lor C$ $A \lor (B \lor C)$ |
... | ... | ... |
$n$ | $W(0) = 1$ $W(n) = \sum\limits_{k=1}^{n-1} W(k)W(n-1-k)$ for $n>0$ |
... |
*For readability, I excluded parentheses around atomics
My goal was to create an algorithm that would take a sentential logic sentence as input and ouput all possible well-formed formulas
For each connective in the sentence, I am treating it as the "major connective", creating a left and right side with respect to it, then recursively performing the same process on the left and right sides until I reach an atomic. Once I reach the atomic, I return it, adding parentheses to the result.
Demonstration of how a sentence is decomposed into a left and right until atomics are reached. The result is returned and concatenated with parentheses and operator.
While recursion is used to decompose and restore parentheses, it is insufficient. An iterative element is used to loop through each connective to treat it as the "major connective".
Together, they are able to cycle through all of the operators, decomposing each into a left and right and reconstructing them as well-formed formulas.
def rec(wff): ind = [] if len(wff) == 1: yield wff return else: for i in range(numConnectives(wff)): opIndex = findConnective(wff, ind) right = createRight(wff, opIndex) left = createLeft(wff, opIndex) for left_subexpr in rec(left): for right_subexpr in rec(right): yield "(" + left_subexpr + ")" + wff[opIndex] + "(" + right_subexpr + ")"
Main recursive algorithm to handle two-place operators written in python
def rec(wff): ind = [] if len(wff) == 1 and wff not in one_place_conn: yield wff return if len(wff) == 2 and one_place_conn in wff and (wff[0] and wff[1] not in one_place_conn): yield "(" + wff + ")" return else: for i in range(numConnectives(numOnePlaceConns(wff), numTwoPlaceConns(wff))): opIndex = findConnective(wff, ind) right = createRight(wff, opIndex) left = createLeft(wff, opIndex) if (wff[opIndex] == one_place_conn): if (len(left) > 0): for left_subexpr in rec(left): for right_subexpr in rec(right): yield "(" + left_subexpr + wff[opIndex] + right_subexpr + ")" else: if (len(right)>1): for right_subexpr in rec(right): yield "(" + wff[opIndex] + right_subexpr + ")" else: break else: for left_subexpr in rec(left): for right_subexpr in rec(right): yield "(" + left_subexpr + wff[opIndex] + right_subexpr + ")"
Addition of the 1-place operator case into the recursive algorithm
Since the 1-place connective case is just a part of a more general algorithm, the algorithm continues on the right side of the one-place connective - regardless if it encounters one or two-place connectives.
Enter SL sentence: -P&Q>-RvS All possible well-formed formulas: 1 (-(P&(Q>(-(RvS))))) 2 (-(P&(Q>((-R)vS)))) 3 (-(P&((Q>(-R))vS))) 4 (-((P&Q)>(-(RvS)))) 5 (-((P&Q)>((-R)vS))) 6 (-((P&(Q>(-R)))vS)) 7 (-(((P&Q)>(-R))vS)) 8 ((-P)&(Q>(-(RvS)))) 9 ((-P)&(Q>((-R)vS))) 10 ((-P)&((Q>(-R))vS)) 11 ((-(P&Q))>(-(RvS))) 12 ((-(P&Q))>((-R)vS)) 13 (((-P)&Q)>(-(RvS))) 14 (((-P)&Q)>((-R)vS)) 15 ((-(P&(Q>(-R))))vS) 16 ((-((P&Q)>(-R)))vS) 17 (((-P)&(Q>(-R)))vS) 18 (((-(P&Q))>(-R))vS) 19 ((((-P)&Q)>(-R))vS)
WFF Possibilities From 2-place Operators
Operators | WFFs Possible |
---|---|
0 | 1 |
1 | 1 |
2 | 2 |
3 | 5 |
4 | 14 |
5 | 42 |
6 | 132 |
7 | 429 |
8 | 1430 |
9 | 4862 |
10 | 16796 |
11 | 58786 |
12 | 208012 |
... | ... |
After looking up this sequence, I found that it was called the Catalan Numbers. These numbers come up in counting problems such as "the number of possible Binary Search Trees with n keys" or "the number of ways an $n$-gon can be divided into $n-2$ traingles". From this project, I found out that they also apply to the number of ways parentheses can be restored to logical sentences with 2-place connectives.