From bae25e220a59f3003bf9d97ecba6a2ea3ba9c82b Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Sat, 18 Sep 2021 19:45:25 +0300 Subject: [PATCH 1/6] add table to output --- turinglab/__main__.py | 2 +- turinglab/input.py | 9 ++++--- turinglab/output.py | 59 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/turinglab/__main__.py b/turinglab/__main__.py index fb96ee2..fb1e220 100644 --- a/turinglab/__main__.py +++ b/turinglab/__main__.py @@ -28,7 +28,7 @@ def main(): tm.step() data.append(tm.info()) - to_docx(args.output_file, data) + to_docx(args.output_file, program, data) if __name__ == '__main__': main() \ No newline at end of file diff --git a/turinglab/input.py b/turinglab/input.py index 755201d..fa35ffc 100644 --- a/turinglab/input.py +++ b/turinglab/input.py @@ -59,16 +59,19 @@ def from_file(filename: str): if 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) if new_symbol == "_": new_symbol = 'λ' new_state = int(new_state) - 1 - program[symbol].append([new_symbol, direction, new_state]) + program[symbol][i] = ([new_symbol, direction, new_state]) f.close() diff --git a/turinglab/output.py b/turinglab/output.py index 1380a6b..834fa9d 100644 --- a/turinglab/output.py +++ b/turinglab/output.py @@ -3,21 +3,66 @@ from docx.oxml import OxmlElement from docx.oxml.ns import qn from docx.shared import Pt 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 to_docx(filename, program, data): 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'] - font = style.font font.name = 'Times New Roman' font.size = Pt(14) + rows = 0 + cols = len(program.keys()) + + for x in program.keys(): + rows = max(list(program[x].keys())[-1] + 1, rows) + + table = document.add_table(rows + 1, cols + 1) + table.style = 'Table Grid' + table.autofit = True + table.allow_autofit = True + + for i in range(1, rows + 1): + p = table.rows[i].cells[0].paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.CENTER + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + 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 + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + p.add_run(x) + + for j, (value) in enumerate(program.values()): + for i, (state, action) in enumerate(value.items()): + p = table.rows[state + 1].cells[j + 1].paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.CENTER + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + + symbol, direction, state = action + add_state(p, state) + p.add_run(symbol) + p.add_run('R' if direction == '>' else 'L') + + p = document.add_paragraph() + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + for i in range(len(data)): p = document.add_paragraph('K') From 71bffa42436522afb49525669199a9e87d03a817 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Sat, 18 Sep 2021 21:08:06 +0300 Subject: [PATCH 2/6] add command list --- turinglab/output.py | 49 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/turinglab/output.py b/turinglab/output.py index 834fa9d..3ab0f78 100644 --- a/turinglab/output.py +++ b/turinglab/output.py @@ -24,13 +24,48 @@ def to_docx(filename, program, data): for x in program.keys(): 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 + + for i in range(rows): + for j in range(cols): + action = program_table[i][j] + if action is None: continue + + p = document.add_paragraph() + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + add_state(p, i) + + symbol, direction, state = action + + p.add_run(symbols[j] + ' → ') + add_state(p, state) + p.add_run(symbol + 'R' if direction == '>' else 'L') + + + p = document.add_paragraph() + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + table = document.add_table(rows + 1, cols + 1) table.style = 'Table Grid' table.autofit = True table.allow_autofit = True - for i in range(1, rows + 1): - p = table.rows[i].cells[0].paragraphs[0] + for i in range(0, rows): + p = table.rows[i + 1].cells[0].paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_after = Pt(0) p.paragraph_format.space_before = Pt(0) @@ -45,9 +80,12 @@ def to_docx(filename, program, data): p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE p.add_run(x) - for j, (value) in enumerate(program.values()): - for i, (state, action) in enumerate(value.items()): - p = table.rows[state + 1].cells[j + 1].paragraphs[0] + 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 p.paragraph_format.space_after = Pt(0) p.paragraph_format.space_before = Pt(0) @@ -58,6 +96,7 @@ def to_docx(filename, program, data): p.add_run(symbol) p.add_run('R' if direction == '>' else 'L') + p = document.add_paragraph() p.paragraph_format.space_after = Pt(0) p.paragraph_format.space_before = Pt(0) From 5ab525210cc74f6880f9c6f60adfc969ec5aa652 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:29:59 +0300 Subject: [PATCH 3/6] add graph generator --- turinglab/__main__.py | 17 +++++++++--- turinglab/image.py | 60 +++++++++++++++++++++++++++++++++++++++++++ turinglab/output.py | 7 +++-- 3 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 turinglab/image.py diff --git a/turinglab/__main__.py b/turinglab/__main__.py index fb1e220..d45286a 100644 --- a/turinglab/__main__.py +++ b/turinglab/__main__.py @@ -1,5 +1,7 @@ +import os import sys from argparse import ArgumentParser +from turinglab.image import get_image from turinglab.input import from_file from turinglab.emulator import Emulator from turinglab.output import to_docx @@ -8,7 +10,7 @@ def get_parser() -> ArgumentParser: parser = ArgumentParser() 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_file", type=str, help="Output file") + parser.add_argument("output_dir", type=str, help="Output dir") return parser @@ -17,9 +19,15 @@ def main(): args = parser.parse_args() - program = from_file(args.input_file) + if os.path.exists(args.output_dir): + print('Directory already exists!') + return -1 + + os.makedirs(args.output_dir) + + tm = Emulator(program, args.input_string) data = [tm.info()] @@ -28,7 +36,10 @@ def main(): tm.step() data.append(tm.info()) - to_docx(args.output_file, program, data) + to_docx(os.path.join(args.output_dir, 'report.docx'), program, data) + + get_image(os.path.join(args.output_dir, 'graph'), program) + if __name__ == '__main__': main() \ No newline at end of file diff --git a/turinglab/image.py b/turinglab/image.py new file mode 100644 index 0000000..7ab4341 --- /dev/null +++ b/turinglab/image.py @@ -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='z>', shape='circle')) + + for i in range(rows): + g.add_node(pydot.Node(f'g{i}', label=f'{i}>', 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) + \ No newline at end of file diff --git a/turinglab/output.py b/turinglab/output.py index 3ab0f78..88daf3e 100644 --- a/turinglab/output.py +++ b/turinglab/output.py @@ -1,7 +1,8 @@ +from turinglab.image import get_image from docx import Document from docx.oxml import OxmlElement 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_ALIGN_PARAGRAPH @@ -22,6 +23,8 @@ def to_docx(filename, program, data): 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 @@ -51,7 +54,7 @@ def to_docx(filename, program, data): p.add_run(symbols[j] + ' → ') add_state(p, state) - p.add_run(symbol + 'R' if direction == '>' else 'L') + p.add_run(symbol + ('R' if direction == '>' else 'L')) p = document.add_paragraph() From 364b6d8aceb92da0aae356e1b71bec77912c74aa Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:33:01 +0300 Subject: [PATCH 4/6] Update README.md --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8d4661f..d0acf94 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,14 @@ turinglab ### Example ```bat -turinglab 0to1to0.tur 101 out.docx +turinglab 0to1to0.tur 101 .\out ``` -Content of ```out.docx```: +Content of ```out\report.docx```: + +![image](https://user-images.githubusercontent.com/36362599/133909049-5d762d15-be1e-471d-9491-a82f54d74d45.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) From 23f8495c384e193d3cd9e964e742b6b96fac7dc7 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Sun, 19 Sep 2021 09:20:51 +0300 Subject: [PATCH 5/6] add support multiple tests --- turinglab/__main__.py | 33 ++++++++++++-------- turinglab/output.py | 71 ++++++++++++++++++++----------------------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/turinglab/__main__.py b/turinglab/__main__.py index d45286a..a916508 100644 --- a/turinglab/__main__.py +++ b/turinglab/__main__.py @@ -6,12 +6,14 @@ from turinglab.input import from_file from turinglab.emulator import Emulator from turinglab.output import to_docx + def get_parser() -> ArgumentParser: parser = ArgumentParser() - 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("input_file", type=str, help="Path to file with program",) parser.add_argument("output_dir", type=str, help="Output dir") - + 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 def main(): @@ -20,24 +22,29 @@ def main(): args = parser.parse_args() program = from_file(args.input_file) - - if os.path.exists(args.output_dir): + + if args.force == False and os.path.exists(args.output_dir): print('Directory already exists!') return -1 - os.makedirs(args.output_dir) - + os.makedirs(args.output_dir, exist_ok=True) - tm = Emulator(program, args.input_string) + test_data = [] - data = [tm.info()] + for test in args.tests: + test = test.replace(args.empty_character, 'λ') - while not tm.stopped: - tm.step() - data.append(tm.info()) + tm = Emulator(program, test) - to_docx(os.path.join(args.output_dir, 'report.docx'), program, data) + 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) diff --git a/turinglab/output.py b/turinglab/output.py index 88daf3e..5157408 100644 --- a/turinglab/output.py +++ b/turinglab/output.py @@ -11,6 +11,16 @@ def add_state(p, state): 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() @@ -44,10 +54,7 @@ def to_docx(filename, program, data): action = program_table[i][j] if action is None: continue - p = document.add_paragraph() - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + p = create_paragraph(document) add_state(p, i) symbol, direction, state = action @@ -57,10 +64,7 @@ def to_docx(filename, program, data): p.add_run(symbol + ('R' if direction == '>' else 'L')) - p = document.add_paragraph() - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + p = create_paragraph(document) table = document.add_table(rows + 1, cols + 1) table.style = 'Table Grid' @@ -70,17 +74,13 @@ def to_docx(filename, program, data): for i in range(0, rows): p = table.rows[i + 1].cells[0].paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + 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 - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + style_paragraph(p) p.add_run(x) for i in range(rows): @@ -90,43 +90,38 @@ def to_docx(filename, program, data): p = table.rows[i + 1].cells[j + 1].paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + 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) - p = document.add_paragraph() - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + for i, test in enumerate(data): + p = create_paragraph(document) + p.add_run(f'Test {i + 1}:') - for i in range(len(data)): - p = document.add_paragraph('K') + for j, data in enumerate(test): + p = create_paragraph(document) + p.add_run('K') - p.paragraph_format.space_after = Pt(0) - p.paragraph_format.space_before = Pt(0) - p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + index_text = p.add_run(str(j)) + index_text.font.subscript = True - index_text = p.add_run(str(i)) - index_text.font.subscript = True + p.add_run(': ') - p.add_run(': ') + head, state, tape = data + offset = list(tape.keys())[0] + head -= offset + tape_str = ''.join(tape.values()) - head, state, tape = data[i] - offset = list(tape.keys())[0] - head -= offset - tape_str = ''.join(tape.values()) + p.add_run(tape_str[:head].lstrip('λ') + 'q') - 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 - 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('λ')) + p.add_run(tape_str[head] + tape_str[head + 1:].rstrip('λ')) document.save(filename) \ No newline at end of file From ab636e08b8beb6cf0db38c4ca765a298c7d425f2 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Sun, 19 Sep 2021 09:22:50 +0300 Subject: [PATCH 6/6] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d0acf94..6f10340 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,16 @@ turinglab ### Example ```bat -turinglab 0to1to0.tur 101 .\out +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\report.docx```: -![image](https://user-images.githubusercontent.com/36362599/133909049-5d762d15-be1e-471d-9491-a82f54d74d45.png) +![image](https://user-images.githubusercontent.com/36362599/133917663-f725d137-e33e-4440-8640-15262120c5bb.png) Content of ```out\graph.svg```: