MA0301/exam_template/python/Hasse.py

83 lines
2.2 KiB
Python

from sys import argv
from pathlib import Path
# Increase if the diagram becomes too clobbered
HEIGHT_SEPARATOR = 1
def printred(text):
print(f'\033[31m{text}\033[0m')
# For manual usage via stdin
def getRels(relations=None):
if relations == None:
relations = input("Write the relations in the following format: ab ac ad bc cd ...\n")
relations = (tuple(list(x)) for x in relations.split(' '))
return set(relations)
# Generate divisibility graph by range
def divisibility_graph(n):
E = set()
for dst in range(n):
for src in range( 1, dst ):
if dst % src == 0:
E.add( ( src, dst ) )
return E
def hasse_diagram(E):
E2 = set()
for e0 in E:
for e1 in E:
if e0[1] == e1[0]:
E2.add( ( e0[0], e1[1] ) )
return E - E2
def latex_hasse(hasse):
min_el = set(a for a,b in hasse if a not in list(zip(*hasse))[1])
keys = set(item for tup in hasse for item in tup)
y_pos = dict.fromkeys(keys, 0)
i = 0
while len(next_row := [val for key,val in hasse if key in [x for x,y in y_pos.items() if y == i] ]) != 0:
for item in next_row:
y_pos[item] = i + 1
i += 1
inv_ypos = dict()
for key in set(y_pos.values()):
inv_ypos[key] = [x for x,y in y_pos.items() if y == key]
output = []
for y in inv_ypos.keys():
for i, n in enumerate(inv_ypos[y]):
output.append(f'\\node ({n}) at ({i - len(inv_ypos[y])/2}, {y * HEIGHT_SEPARATOR}) {{${n}$}};')
output.append('')
for x,y in hasse:
output.append(f'\\draw ({x}) -- ({y});')
printred(f"Minimal elements: $\{{ {', '.join(str(e) for e in min_el)} \}}$ \\\\")
max_el = set(v for k,v in hasse if v not in (x for x,_ in hasse))
printred(f"Maximal elements: $\{{ {', '.join(str(e) for e in max_el)} \}}$" )
return '\n'.join(output)
if __name__ == '__main__':
filename = argv[1]
with open(filename) as file:
rels = getRels(file.read())
# rels = getRels()
# rels = divisibility_graph(30)
content = latex_hasse(hasse_diagram(rels))
with open(str(Path(__file__).parent.absolute()) + '/tex_templates/Hasse.tex') as template:
with open(argv[2], 'w') as destination_file:
destination_file.write(template.read().replace('%CONTENT', content))