-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLogicReducer.py
141 lines (116 loc) · 5.25 KB
/
LogicReducer.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
# **************************************************************************************************
# @file LogicReducer.py
# @brief converts a truth table stored into a text file into a list of minterms. These are fed to
# the C++ Petrick program so that they get reduced. With this program you will get all the reduced
# expressions for the columns at the right of the truth table.
#
# @project Logic Function Reducer
# @version 1.0
# @date 2024-09-15
# @author @dabecart
#
# @license
# This project is licensed under the MIT License - see the LICENSE file for details.
# **************************************************************************************************
import shlex, os, subprocess
import argparse
# Verifies if the provided filepath is a valid, readable file.
def verifyFile(filepath: str) -> bool:
# Check if the file exists
if not os.path.exists(filepath):
print(f"Error: The file '{filepath}' does not exist.")
return False
# Check if the filepath is a file (not a directory)
if not os.path.isfile(filepath):
print(f"Error: The path '{filepath}' is not a file.")
return False
# Check if the file is readable
if not os.access(filepath, os.R_OK):
print(f"Error: The file '{filepath}' is not readable.")
return False
return True
def fromRowToNumbers(input: str) -> list[int]:
ret = []
if 'x' in input:
ret.extend(fromRowToNumbers(input.replace('x', '0', 1)))
ret.extend(fromRowToNumbers(input.replace('x', '1', 1)))
else:
input = input.replace(' ', '')
ret.append(int(input, 2))
return ret
def executeCommand(cmd: str, cwd: str):
commandArgs = shlex.split(cmd)
# So that the windowed application doesn't open a terminal to run the code on Windows (nt).
# Taken from here:
# https://code.activestate.com/recipes/409002-launching-a-subprocess-without-a-console-window/
if os.name == 'nt':
startupInfo = subprocess.STARTUPINFO()
startupInfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
runResult = subprocess.run(commandArgs,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
cwd = cwd,
startupinfo = startupInfo)
else:
runResult = subprocess.run(commandArgs,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
cwd = cwd)
# Taken from here:
# https://stackoverflow.com/questions/24849998/how-to-catch-exception-output-from-python-subprocess-check-output
if runResult.stderr:
raise subprocess.CalledProcessError(
returncode = runResult.returncode,
cmd = runResult.args,
stderr = runResult.stderr
)
print(runResult.stdout.decode('utf-8'))
def main():
parser = argparse.ArgumentParser(
prog="LogicReducer.py",
description="Process the truth table from a file and reduce to its maximally reduced\n"
"algebraic expression. Inputs are labeled a to z, outputs Q0 to Q9, from left\n"
"to right.",
epilog="By @dabecart, 2024.")
parser.add_argument('-v', '--verbose', action='store_true',
help='Verbose mode displays more info on the process.')
parser.add_argument('-c', '--colored', action='store_true',
help='Negated terms shown in red, non-negated in green.')
parser.add_argument('file', type=str,
help='The path to the text file containing the truth table.')
args = parser.parse_args()
if not verifyFile(args.file):
exit(-1)
# Store all the functions.
minterms: list[list[int]] = []
dnc: list[list[int]] = []
cwd = os.path.dirname(os.path.abspath(__file__))
with open(args.file) as f:
lines = f.readlines()
inputCount = len(lines[0].split('|')[0].strip().split(" "))
outFuncCount = len(lines[0].split('|')[1].strip().split(" "))
minterms = [[] for i in range(outFuncCount)]
dnc = [[] for i in range(outFuncCount)]
for line in lines:
line = line.split("|")
inputs: list[int] = fromRowToNumbers(line[0].strip())
outputs: list[str] = line[1].strip().split(' ')
for index, out in enumerate(outputs):
if out == '1':
minterms[index].extend(inputs)
elif out == 'x':
dnc[index].extend(inputs)
for index, (m, d) in enumerate(zip(minterms, dnc)):
print(f"Q{index}: {m}")
print(f"DNC{index}: {d}")
mstr = str(m).replace(" ", "")
dstr = str(d).replace(" ", "")
optionalArgs = ""
if args.verbose: optionalArgs += "-v "
if args.colored: optionalArgs += "-c"
if os.name == 'nt':
executeCommand(f"petrick.exe {optionalArgs} {inputCount} {mstr} {dstr}", cwd)
else:
executeCommand(f"./petrick {optionalArgs} {inputCount} {mstr} {dstr}", cwd)
if __name__ == "__main__":
main()