commit
173d18e21e
15
README.md
15
README.md
@ -21,9 +21,18 @@ turinglab <input_file> <input_string> <output_file>
|
|||||||
### Example
|
### Example
|
||||||
|
|
||||||
```bat
|
```bat
|
||||||
turinglab 0to1to0.txt 101 out.docx
|
turinglab 0to1to0.txt .\out -t 101 1E -e E -f
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```bat
|
||||||
|
turinglab 0to1to0.txt .\out --tests 101 1E --empty-character E --force
|
||||||
```
|
```
|
||||||
|
|
||||||
Content of ```out.docx```:
|
Content of ```out\report.docx```:
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/36362599/133917663-f725d137-e33e-4440-8640-15262120c5bb.png)
|
||||||
|
|
||||||
|
Content of ```out\graph.svg```:
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/36362599/133909074-e1928d40-263f-4c80-94ef-4ae495662419.png)
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/36362599/133625379-0624f6ab-b43b-40de-83e7-6495ee03c45b.png)
|
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
from turinglab.image import get_image
|
||||||
from turinglab.input import from_file
|
from turinglab.input import from_file
|
||||||
from turinglab.emulator import Emulator
|
from turinglab.emulator import Emulator
|
||||||
from turinglab.output import to_docx
|
from turinglab.output import to_docx
|
||||||
|
|
||||||
|
|
||||||
def get_parser() -> ArgumentParser:
|
def get_parser() -> ArgumentParser:
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
parser.add_argument("input_file", type=str, help="Path to file with program")
|
parser.add_argument("input_file", type=str, help="Path to file with program",)
|
||||||
parser.add_argument("input_string", type=str, help="Input symbols")
|
parser.add_argument("output_dir", type=str, help="Output dir")
|
||||||
parser.add_argument("output_file", type=str, help="Output file")
|
parser.add_argument('-t','--tests', nargs='+', type=str, help='List of input strings for tests')
|
||||||
|
parser.add_argument('-e','--empty-character', type=str, help='Empty character')
|
||||||
|
parser.add_argument('-f','--force', default=False, action='store_true', help='Force rewrite output dir')
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -17,18 +21,32 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
program = from_file(args.input_file)
|
program = from_file(args.input_file)
|
||||||
|
|
||||||
|
if args.force == False and os.path.exists(args.output_dir):
|
||||||
|
print('Directory already exists!')
|
||||||
|
return -1
|
||||||
|
|
||||||
tm = Emulator(program, args.input_string)
|
os.makedirs(args.output_dir, exist_ok=True)
|
||||||
|
|
||||||
data = [tm.info()]
|
test_data = []
|
||||||
|
|
||||||
while not tm.stopped:
|
for test in args.tests:
|
||||||
tm.step()
|
test = test.replace(args.empty_character, 'λ')
|
||||||
data.append(tm.info())
|
|
||||||
|
tm = Emulator(program, test)
|
||||||
|
|
||||||
|
data = [tm.info()]
|
||||||
|
|
||||||
|
while not tm.stopped:
|
||||||
|
tm.step()
|
||||||
|
data.append(tm.info())
|
||||||
|
|
||||||
|
test_data.append(data)
|
||||||
|
|
||||||
|
to_docx(os.path.join(args.output_dir, 'report.docx'), program, test_data)
|
||||||
|
get_image(os.path.join(args.output_dir, 'graph'), program)
|
||||||
|
|
||||||
to_docx(args.output_file, data)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
60
turinglab/image.py
Normal file
60
turinglab/image.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import pydot
|
||||||
|
import requests
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def get_image(filename, program):
|
||||||
|
g = pydot.Dot('my_graph', nodesep=0.5)
|
||||||
|
g.set_node_defaults(
|
||||||
|
width='1.5',
|
||||||
|
fontsize='18',
|
||||||
|
shape='circle'
|
||||||
|
)
|
||||||
|
|
||||||
|
rows = 0
|
||||||
|
cols = len(program.keys())
|
||||||
|
|
||||||
|
for x in program.keys():
|
||||||
|
if len(list(program[x].keys())) == 0:
|
||||||
|
continue
|
||||||
|
rows = max(list(program[x].keys())[-1] + 1, rows)
|
||||||
|
|
||||||
|
program_table = [None] * rows
|
||||||
|
|
||||||
|
for i in range(rows):
|
||||||
|
program_table[i] = [None] * cols
|
||||||
|
|
||||||
|
symbols = [None] * cols
|
||||||
|
|
||||||
|
for j, (symbol, value) in enumerate(program.items()):
|
||||||
|
symbols[j] = symbol
|
||||||
|
for i, (state, action) in enumerate(value.items()):
|
||||||
|
program_table[state][j] = action
|
||||||
|
|
||||||
|
g.add_node(pydot.Node(f'gz', label='<g<SUB>z</SUB>>', shape='circle'))
|
||||||
|
|
||||||
|
for i in range(rows):
|
||||||
|
g.add_node(pydot.Node(f'g{i}', label=f'<g<SUB>{i}</SUB>>', shape='circle'))
|
||||||
|
for j in range(cols):
|
||||||
|
action = program_table[i][j]
|
||||||
|
if action is None: continue
|
||||||
|
|
||||||
|
symbol, direction, state = action
|
||||||
|
label = symbols[j] + '/' + symbol + '/' + ('R' if direction == '>' else 'L')
|
||||||
|
src = f'g{i}'
|
||||||
|
dst = f'g{"z" if state == -1 else state}'
|
||||||
|
if src == dst:
|
||||||
|
src = src + ':ne'
|
||||||
|
dst = dst + ':se'
|
||||||
|
g.add_edge(pydot.Edge(src, dst, label = label))
|
||||||
|
|
||||||
|
|
||||||
|
g.write_raw(f'{filename}.dot', encoding='utf-8')
|
||||||
|
|
||||||
|
try:
|
||||||
|
g.write_svg(f'{filename}.svg', encoding='utf-8')
|
||||||
|
except Exception:
|
||||||
|
output_raw_dot = g.to_string()
|
||||||
|
img_data = requests.get("https://quickchart.io/graphviz?graph=" + output_raw_dot).content
|
||||||
|
with open(f'{filename}_quickchart.svg', 'wb') as handler:
|
||||||
|
handler.write(img_data)
|
||||||
|
|
@ -59,16 +59,19 @@ def from_file(filename: str):
|
|||||||
if symbol == " ":
|
if symbol == " ":
|
||||||
symbol = "λ"
|
symbol = "λ"
|
||||||
|
|
||||||
program[symbol] = []
|
program[symbol] = dict()
|
||||||
|
|
||||||
|
for i, action in enumerate(actions):
|
||||||
|
if not action:
|
||||||
|
continue
|
||||||
|
|
||||||
for action in actions:
|
|
||||||
new_symbol, direction, new_state = list(action)
|
new_symbol, direction, new_state = list(action)
|
||||||
|
|
||||||
if new_symbol == "_":
|
if new_symbol == "_":
|
||||||
new_symbol = 'λ'
|
new_symbol = 'λ'
|
||||||
new_state = int(new_state) - 1
|
new_state = int(new_state) - 1
|
||||||
|
|
||||||
program[symbol].append([new_symbol, direction, new_state])
|
program[symbol][i] = ([new_symbol, direction, new_state])
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
@ -1,45 +1,127 @@
|
|||||||
|
from turinglab.image import get_image
|
||||||
from docx import Document
|
from docx import Document
|
||||||
from docx.oxml import OxmlElement
|
from docx.oxml import OxmlElement
|
||||||
from docx.oxml.ns import qn
|
from docx.oxml.ns import qn
|
||||||
from docx.shared import Pt
|
from docx.shared import Pt, Inches
|
||||||
from docx.enum.text import WD_LINE_SPACING
|
from docx.enum.text import WD_LINE_SPACING
|
||||||
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||||
|
|
||||||
def to_docx(filename, data):
|
def add_state(p, state):
|
||||||
|
p.add_run('q')
|
||||||
|
index_text = p.add_run(str('z' if state == -1 else state))
|
||||||
|
index_text.font.subscript = True
|
||||||
|
|
||||||
|
def create_paragraph(document):
|
||||||
|
p = document.add_paragraph()
|
||||||
|
style_paragraph(p)
|
||||||
|
return p
|
||||||
|
|
||||||
|
def style_paragraph(p):
|
||||||
|
p.paragraph_format.space_after = Pt(0)
|
||||||
|
p.paragraph_format.space_before = Pt(0)
|
||||||
|
p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
|
||||||
|
|
||||||
|
def to_docx(filename, program, data):
|
||||||
document = Document()
|
document = Document()
|
||||||
section = document.sections[0]
|
|
||||||
|
|
||||||
sectPr = section._sectPr
|
|
||||||
cols = sectPr.xpath('./w:cols')[0]
|
|
||||||
cols.set(qn('w:num'),'2')
|
|
||||||
|
|
||||||
style = document.styles['Normal']
|
style = document.styles['Normal']
|
||||||
|
|
||||||
font = style.font
|
font = style.font
|
||||||
font.name = 'Times New Roman'
|
font.name = 'Times New Roman'
|
||||||
font.size = Pt(14)
|
font.size = Pt(14)
|
||||||
|
|
||||||
for i in range(len(data)):
|
rows = 0
|
||||||
p = document.add_paragraph('K')
|
cols = len(program.keys())
|
||||||
|
|
||||||
p.paragraph_format.space_after = Pt(0)
|
for x in program.keys():
|
||||||
p.paragraph_format.space_before = Pt(0)
|
if len(list(program[x].keys())) == 0:
|
||||||
p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE
|
continue
|
||||||
|
rows = max(list(program[x].keys())[-1] + 1, rows)
|
||||||
|
|
||||||
index_text = p.add_run(str(i))
|
program_table = [None] * rows
|
||||||
index_text.font.subscript = True
|
|
||||||
|
|
||||||
p.add_run(': ')
|
for i in range(rows):
|
||||||
|
program_table[i] = [None] * cols
|
||||||
|
|
||||||
head, state, tape = data[i]
|
symbols = [None] * cols
|
||||||
offset = list(tape.keys())[0]
|
|
||||||
head -= offset
|
|
||||||
tape_str = ''.join(tape.values())
|
|
||||||
|
|
||||||
p.add_run(tape_str[:head].lstrip('λ') + 'q')
|
for j, (symbol, value) in enumerate(program.items()):
|
||||||
|
symbols[j] = symbol
|
||||||
|
for i, (state, action) in enumerate(value.items()):
|
||||||
|
program_table[state][j] = action
|
||||||
|
|
||||||
|
for i in range(rows):
|
||||||
|
for j in range(cols):
|
||||||
|
action = program_table[i][j]
|
||||||
|
if action is None: continue
|
||||||
|
|
||||||
index_text = p.add_run(str('z' if state == -1 else state))
|
p = create_paragraph(document)
|
||||||
index_text.font.subscript = True
|
add_state(p, i)
|
||||||
|
|
||||||
p.add_run(tape_str[head] + tape_str[head + 1:].rstrip('λ'))
|
symbol, direction, state = action
|
||||||
|
|
||||||
|
p.add_run(symbols[j] + ' → ')
|
||||||
|
add_state(p, state)
|
||||||
|
p.add_run(symbol + ('R' if direction == '>' else 'L'))
|
||||||
|
|
||||||
|
|
||||||
|
p = create_paragraph(document)
|
||||||
|
|
||||||
|
table = document.add_table(rows + 1, cols + 1)
|
||||||
|
table.style = 'Table Grid'
|
||||||
|
table.autofit = True
|
||||||
|
table.allow_autofit = True
|
||||||
|
|
||||||
|
for i in range(0, rows):
|
||||||
|
p = table.rows[i + 1].cells[0].paragraphs[0]
|
||||||
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||||
|
style_paragraph(p)
|
||||||
|
add_state(p, i)
|
||||||
|
|
||||||
|
for i, x in enumerate(program.keys()):
|
||||||
|
p = table.rows[0].cells[i + 1].paragraphs[0]
|
||||||
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||||
|
style_paragraph(p)
|
||||||
|
p.add_run(x)
|
||||||
|
|
||||||
|
for i in range(rows):
|
||||||
|
for j in range(cols):
|
||||||
|
action = program_table[i][j]
|
||||||
|
if action is None: continue
|
||||||
|
|
||||||
|
p = table.rows[i + 1].cells[j + 1].paragraphs[0]
|
||||||
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||||
|
style_paragraph(p)
|
||||||
|
|
||||||
|
symbol, direction, state = action
|
||||||
|
add_state(p, state)
|
||||||
|
p.add_run(symbol)
|
||||||
|
p.add_run('R' if direction == '>' else 'L')
|
||||||
|
|
||||||
|
p = create_paragraph(document)
|
||||||
|
|
||||||
|
for i, test in enumerate(data):
|
||||||
|
p = create_paragraph(document)
|
||||||
|
p.add_run(f'Test {i + 1}:')
|
||||||
|
|
||||||
|
for j, data in enumerate(test):
|
||||||
|
p = create_paragraph(document)
|
||||||
|
p.add_run('K')
|
||||||
|
|
||||||
|
index_text = p.add_run(str(j))
|
||||||
|
index_text.font.subscript = True
|
||||||
|
|
||||||
|
p.add_run(': ')
|
||||||
|
|
||||||
|
head, state, tape = data
|
||||||
|
offset = list(tape.keys())[0]
|
||||||
|
head -= offset
|
||||||
|
tape_str = ''.join(tape.values())
|
||||||
|
|
||||||
|
p.add_run(tape_str[:head].lstrip('λ') + 'q')
|
||||||
|
|
||||||
|
index_text = p.add_run(str('z' if state == -1 else state))
|
||||||
|
index_text.font.subscript = True
|
||||||
|
|
||||||
|
p.add_run(tape_str[head] + tape_str[head + 1:].rstrip('λ'))
|
||||||
|
|
||||||
document.save(filename)
|
document.save(filename)
|
Loading…
Reference in New Issue
Block a user