Skip to content

Instantly share code, notes, and snippets.

@WitherOrNot
Last active August 30, 2020 17:43
Show Gist options
  • Select an option

  • Save WitherOrNot/0464e5f802a22e2a307c42831f050cf0 to your computer and use it in GitHub Desktop.

Select an option

Save WitherOrNot/0464e5f802a22e2a307c42831f050cf0 to your computer and use it in GitHub Desktop.
Truth Table Generator
?start: arrow
?arrow: operator
| arrow "->" operator -> conditional
| arrow "<>" operator -> biconditional
?operator: atom
| operator "^" atom -> conjunction
| operator "v" atom -> disjunction
?atom: UCASE_LETTER -> symbol
| "-" atom -> negation
| "(" arrow ")"
%import common.WS_INLINE
%import common.UCASE_LETTER
%ignore WS_INLINE
from lark import Lark, Visitor, v_args
from rich.console import Console
from rich.table import Table
import sys
def unparse(tree):
if tree.data not in ["negation", "symbol"]:
left = tree.children[0]
right = tree.children[1]
upleft = unparse(left) if left.data in ["negation", "symbol"] else f"({unparse(left)})"
upright = unparse(right) if right.data in ["negation", "symbol"] else f"({unparse(right)})"
op = {
"biconditional": "<>",
"conditional": "->",
"conjunction": "^",
"disjunction": "v"
}[tree.data]
return f"{upleft} {op} {upright}"
elif tree.data == "negation":
child = tree.children[0]
upchild = unparse(child) if child.data == "symbol" else f"({unparse(child)})"
return f"-{upchild}"
elif tree.data == "symbol":
return tree.children[0].value
def input_vals(n):
vals = []
for i in range(1<<n):
vals.append([q == "1" for q in bin(i)[2:].zfill(n)])
return vals[::-1]
def eval_tree(tree, symvals):
if tree.data == "symbol":
return symvals[tree.children[0].value]
elif tree.data == "negation":
return not eval_tree(tree.children[0], symvals)
elif tree.data == "conjunction":
left = tree.children[0]
right = tree.children[1]
return eval_tree(left, symvals) and eval_tree(right, symvals)
elif tree.data == "disjunction":
left = tree.children[0]
right = tree.children[1]
return eval_tree(left, symvals) or eval_tree(right, symvals)
elif tree.data == "conditional":
left = tree.children[0]
right = tree.children[1]
return (not eval_tree(left, symvals)) or eval_tree(right, symvals)
elif tree.data == "biconditional":
left = tree.children[0]
right = tree.children[1]
return eval_tree(left, symvals) == eval_tree(right, symvals)
def truth_column(tree, symbols):
ivals = input_vals(len(symbols))
column = []
for vals in ivals:
symvals = dict(zip(symbols, vals))
column.append(eval_tree(tree, symvals))
return column
class SymbolEnumerator(Visitor):
symbols = []
def symbol(self, tree):
sym = tree.children[0].value
if sym not in self.symbols:
self.symbols.append(sym)
self.symbols.sort()
class TruthTable(Visitor):
symbols = []
columns = {}
def negation(self, tree):
self.columns[unparse(tree)] = truth_column(tree, self.symbols)
def conjunction(self, tree):
self.columns[unparse(tree)] = truth_column(tree, self.symbols)
def disjunction(self, tree):
self.columns[unparse(tree)] = truth_column(tree, self.symbols)
def conditional(self, tree):
self.columns[unparse(tree)] = truth_column(tree, self.symbols)
def biconditional(self, tree):
self.columns[unparse(tree)] = truth_column(tree, self.symbols)
def create_table(self):
table = {}
ivals = [list(x) for x in zip(*input_vals(len(self.symbols)))]
for i in range(len(self.symbols)):
table[self.symbols[i]] = ivals[i]
for col in self.columns:
table[col] = self.columns[col]
self.table = table
return self.table
def gen_table(self, tree):
symenum = SymbolEnumerator()
symenum.visit(tree)
self.symbols = symenum.symbols
self.visit(tree)
return self.create_table()
def print_table(self, binary=False):
rtable = Table(*self.table.keys())
rows = zip(*self.table.values())
alpha = "01" if binary else "FT"
for row in rows:
row = [alpha[x] for x in row]
rtable.add_row(*row)
console = Console()
console.print(rtable)
if __name__ == "__main__":
l = Lark(open("boolean.lark", "r"), parser="lalr")
tree = l.parse(input("Expression: "))
table = TruthTable()
table.gen_table(tree)
table.print_table(binary=("-b" in sys.argv or "--binary" in sys.argv))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment