-
Notifications
You must be signed in to change notification settings - Fork 0
/
TruthAndVoltage.py
159 lines (139 loc) · 5.74 KB
/
TruthAndVoltage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import re, collections
def tokenizer(raw_str): # break raw (user) input to meaningful chunks
pos = 0
while pos < len(raw_str):
if re.match(r'[+*/]', raw_str[pos]):
yield ('OP', raw_str[pos])
elif re.match(r'\w', raw_str[pos]):
variable = raw_str[pos]
var_pos = pos + 1
while var_pos < len(raw_str) and re.match(r'[\w]', raw_str[var_pos]):
variable += raw_str[var_pos]
var_pos += 1
pos = var_pos - 1
yield ('VAR', variable)
elif raw_str[pos] == ')':
yield (')', raw_str[pos])
elif raw_str[pos] == '(':
yield ('(', raw_str[pos])
else:
print("Error: invalid character detected:", raw_str[pos])
exit()
pos += 1
def populateVectors(vect_tokens): # populate the variables with all T/F combinations
dict = collections.OrderedDict()
length = len(vect_tokens)
for i in range(length):
vect = []
for j in range(2**i):
vect += [False for num in range(2**(length-(i+1)))]
vect += [True for num in range(2**(length-(i+1)))]
dict[vect_tokens[i][1]] = vect #extract variable name and populate it
return dict
def _cmp_prc(lhs,rhs): # compare precedence
precedence = {'+' : 0 , '*' : 1, '/': 2}
return precedence[lhs] - precedence[rhs]
def to_RPN(tokens): # convert using Shunting Yard algorithm to Reverse Polish notation
RPN_tokens = []
opStack =[]
for tokenType, tokenVal in tokens:
if tokenType == "VAR":
RPN_tokens.append((tokenType, tokenVal))
elif tokenType == "OP":
while len(opStack):
topType, topVal = opStack[-1]
if topType == '(' or topType == ')': break
if tokenVal != '/' and _cmp_prc(tokenVal,topVal) <= 0:
RPN_tokens.append(opStack.pop())
else: break
opStack.append((tokenType, tokenVal))
elif tokenType == '(':
opStack.append((tokenType, tokenVal))
elif tokenType == ')':
while len(opStack):
topType, topVal = opStack[-1]
if topType == '(': break
RPN_tokens.append(opStack.pop())
try:
topType, topVal = opStack[-1]
if topType != '(': raise RuntimeError
except RuntimeError:
print("Error: mismatch(1) in parenthesis.")
exit()
opStack.pop()
while len(opStack) > 0:
topType, topVal = opStack[-1]
if topType == ')' or topType == '(':
print("Error: mismatch(2) in parenthesis.")
exit()
RPN_tokens.append(opStack.pop())
return RPN_tokens
def _perform_op(op, *args): # execute the operation on each element of the vector
if len(args) == 2: # binary operation
vect1, vect2 = args
assert len(vect1) == len(vect2)
result = []
for index in range(len(vect1)):
result.append(op(vect1[index],vect2[index]))
return result
elif len(args) == 1: # unary operation
vect = args[0]
return [op(x) for x in vect]
else: raise RuntimeError # invalid operation
def compute_tt(RPN_tokens,dict): # compute truth table result vector
calc_stack = []
for tokenType,tokenVal in RPN_tokens:
if tokenType == 'OP':
if not calc_stack: # validate unary operator
print("Error: invalid placement of {0} operator".format(tokenVal))
exit()
if tokenVal == '/':
vect = calc_stack.pop()
negated_vect = _perform_op(lambda x: not x,vect)
calc_stack.append(negated_vect)
continue
if len(calc_stack) < 2: # validate binary operator
print("Error: invalid placement of {0} operator".format(tokenVal))
exit()
vect1, vect2 = calc_stack.pop(), calc_stack.pop()
result = None
if tokenVal == '+':
result = _perform_op(lambda x,y: x or y,vect1,vect2)
elif tokenVal == '*':
result = _perform_op(lambda x,y: x and y,vect1,vect2)
else: raise RuntimeError
calc_stack.append(result)
continue
elif tokenType == 'VAR':
calc_stack.append(dict[tokenVal])
else: raise RuntimeError
return calc_stack[-1]
def compute_vt(RPN_tokens,dict): # compute voltage table result vector
vtDict = dict.copy() # voltage-table dict will have all active low negated
for var_name, vect in dict.items(): # negate all the active low vectors
if re.match(r'(.*)_L',var_name):
vtDict[var_name] = _perform_op(lambda x: not x,vect)
return compute_tt(RPN_tokens,vtDict)
def print_table(dict,result,t_val,f_val):
for var_name in dict.keys():
print(var_name,end='\t\t')
else: print()
for index in range(2**len(dict)):
for vect in dict.values():
print(t_val if vect[index] else f_val, end='\t\t')
else: print(t_val if result[index] else f_val)
def main():
tokens = [token for token in tokenizer(input("> "))]
seen = set() # used for extracting unique variable names and preserving order
variable_names = [x for x in tokens if not (x in seen or seen.add(x) or x[0] != 'VAR')]
dict = populateVectors(variable_names)
RPN_tokens = to_RPN(tokens)
print("Truth Table:")
tt_result = compute_tt(RPN_tokens,dict) # result vector for truth table
print_table(dict,tt_result,'1','0')
print()
print("Voltage Table:")
vt_result = compute_vt(RPN_tokens,dict) # result vector for truth table
print_table(dict,vt_result,'H','L')
if __name__ == "__main__":
main()