Merge pull request #2 from Maks1mS/dev

Dev
This commit is contained in:
Maxim Slipenko 2021-09-19 09:24:02 +03:00 committed by GitHub
commit 173d18e21e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 213 additions and 41 deletions

View File

@ -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)

View File

@ -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
View 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)

View File

@ -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()

View File

@ -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)