Several updates
This commit is contained in:
parent
f440e3cb4c
commit
a2f9fdbe09
|
@ -2,7 +2,7 @@ from sys import argv
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from math import sin, cos, pi
|
from math import sin, cos, pi
|
||||||
|
|
||||||
# from run import printred
|
from common import printc
|
||||||
|
|
||||||
class Matrix:
|
class Matrix:
|
||||||
""" Adjacency matrix which supports 0 and 1 """
|
""" Adjacency matrix which supports 0 and 1 """
|
||||||
|
@ -59,12 +59,12 @@ class Matrix:
|
||||||
|
|
||||||
|
|
||||||
class Graph:
|
class Graph:
|
||||||
def __init__(self, nodes, edges):
|
def __init__(self, nodes, edges): # Nodes = str, Edges = (str,str)
|
||||||
self.nodes = nodes
|
self.nodes = nodes
|
||||||
self.edges = edges
|
self.edges = edges
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
print(self.isUndirected())
|
printc('Is undirected: ' + str(self.isUndirected()))
|
||||||
return \
|
return \
|
||||||
f'Nodes: {" ".join(self.nodes)}\n' \
|
f'Nodes: {" ".join(self.nodes)}\n' \
|
||||||
+ f'Edges: {" ".join(x+y for x,y in (self.undirectedEdgeSet() if self.isUndirected() else self.edges))}'
|
+ f'Edges: {" ".join(x+y for x,y in (self.undirectedEdgeSet() if self.isUndirected() else self.edges))}'
|
||||||
|
@ -117,6 +117,34 @@ class Graph:
|
||||||
edges = sorted(list(set((x,y) if x < y else (y,x) for x,y in edges)))
|
edges = sorted(list(set((x,y) if x < y else (y,x) for x,y in edges)))
|
||||||
return edges
|
return edges
|
||||||
|
|
||||||
|
# def latexifyEulerPath(self):
|
||||||
|
# degrees = [sum(line) for line in self.toMatrix()]
|
||||||
|
|
||||||
|
# def latexifyEulerCircuit():
|
||||||
|
# pass
|
||||||
|
|
||||||
|
def getKruskalsSpanningTree(self, weigths): # weights = dict[str, int]
|
||||||
|
edges = []
|
||||||
|
connected_subgraphs = [set(v) for v in self.nodes]
|
||||||
|
|
||||||
|
def find_subgraph_containing(v):
|
||||||
|
return [x for x in connected_subgraphs if v in x][0]
|
||||||
|
|
||||||
|
def merge_subgraphs_that_contains(u, v):
|
||||||
|
subgraph_v = find_subgraph_containing(v)
|
||||||
|
new_connected_subgraphs = [x for x in connected_subgraphs if v not in x]
|
||||||
|
new_connected_subgraphs = [subgraph_v.union(x) if u in x else x for x in new_connected_subgraphs]
|
||||||
|
return new_connected_subgraphs
|
||||||
|
|
||||||
|
sorted_edges = [ e for e in sorted(self.edges, key=lambda e: weigths[str(e)]) ]
|
||||||
|
|
||||||
|
for u,v in sorted_edges:
|
||||||
|
if find_subgraph_containing(u) != find_subgraph_containing(v):
|
||||||
|
edges += [(u, v)]
|
||||||
|
connected_subgraphs = merge_subgraphs_that_contains(u, v)
|
||||||
|
|
||||||
|
return Graph(self.nodes, edges)
|
||||||
|
|
||||||
def toLaTeX(self):
|
def toLaTeX(self):
|
||||||
zippedNodes = zip(self.nodes, generateNodeCoords(len(self.nodes)))
|
zippedNodes = zip(self.nodes, generateNodeCoords(len(self.nodes)))
|
||||||
nodeString = '\n'.join(f'\\node ({name}) at ({x},{y}) {{${name}$}};' for name,(x,y) in zippedNodes)
|
nodeString = '\n'.join(f'\\node ({name}) at ({x},{y}) {{${name}$}};' for name,(x,y) in zippedNodes)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from sys import argv
|
from sys import argv
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from run import printred
|
from common import printc
|
||||||
|
|
||||||
# Increase if the diagram becomes too clobbered
|
# Increase if the diagram becomes too clobbered
|
||||||
HEIGHT_SEPARATOR = 1
|
HEIGHT_SEPARATOR = 1
|
||||||
|
@ -57,10 +57,10 @@ def latex_hasse(hasse):
|
||||||
output.append(f'\\draw ({x}) -- ({y});')
|
output.append(f'\\draw ({x}) -- ({y});')
|
||||||
|
|
||||||
|
|
||||||
printred(f"Minimal elements: $\{{ {', '.join(str(e) for e in min_el)} \}}$ \\\\")
|
printc(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))
|
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)} \}}$" )
|
printc(f"Maximal elements: $\{{ {', '.join(str(e) for e in max_el)} \}}$" )
|
||||||
|
|
||||||
return '\n'.join(output)
|
return '\n'.join(output)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
from itertools import combinations
|
||||||
|
|
||||||
|
class Set:
|
||||||
|
def __init__(self, elements):
|
||||||
|
self.elements = set(elements)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if len(self) == 0: return "\\emptyset"
|
||||||
|
return f"\\{{ {', '.join(sorted(self.elements))} \\}}"
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return list(sorted(self.elements))
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.elements)
|
||||||
|
|
||||||
|
def __gt__(self, value):
|
||||||
|
if len(self) != len(value):
|
||||||
|
return len(self) > len(value)
|
||||||
|
return self.elements > value.elements
|
||||||
|
|
||||||
|
def __ge__(self, value):
|
||||||
|
return self > value
|
||||||
|
|
||||||
|
def __lt__(self, value):
|
||||||
|
return not self > value
|
||||||
|
|
||||||
|
def __le__(self, value):
|
||||||
|
return self < value
|
||||||
|
|
||||||
|
def cardinality(self):
|
||||||
|
return len(self)
|
||||||
|
|
||||||
|
def powerset(self):
|
||||||
|
powerset = []
|
||||||
|
for i in range(len(self) + 1):
|
||||||
|
for subset in combinations(self.elements, i):
|
||||||
|
powerset.append(Set(list(subset)))
|
||||||
|
return Set(powerset)
|
||||||
|
|
||||||
|
def to_vertical_latex(self):
|
||||||
|
column = []
|
||||||
|
for e in sorted(self.elements):
|
||||||
|
column.append(str(e) + ' \\\\')
|
||||||
|
return '\\{\n' + '\n'.join(column) + '\n\\}'
|
||||||
|
|
||||||
|
#TODO: make process input func
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(Set(['a', 'b', 'c']).powerset().to_vertical_latex())
|
||||||
|
# print(a for a in Set(['A', 'B', 'C']).powerset())
|
|
@ -0,0 +1,182 @@
|
||||||
|
from sys import argv
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from common import printc, printerr
|
||||||
|
from Graph import Graph
|
||||||
|
|
||||||
|
# Increase if hasse diagram becomes too clobbered
|
||||||
|
HEIGHT_SEPARATOR = 1
|
||||||
|
|
||||||
|
def pairToString(pair):
|
||||||
|
if str(pair[0]).isdigit() or str(pair[1]).isdigit():
|
||||||
|
return f'({pair[0]},{pair[1]})'
|
||||||
|
else:
|
||||||
|
return pair[0] + pair[1]
|
||||||
|
|
||||||
|
def stringToPair(string):
|
||||||
|
if string[0] == '(':
|
||||||
|
return tuple(string.split(',')[0][1:], string.split(',')[0][:-1])
|
||||||
|
else:
|
||||||
|
return tuple(list(string))
|
||||||
|
|
||||||
|
|
||||||
|
class Relation:
|
||||||
|
def __init__(self, pairs): # pair = (str,str)
|
||||||
|
self.pairs = set(pairs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'\\{{ {", ".join(x + y for x,y in self.pairs)} \}}'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fromString(cls, string):
|
||||||
|
relations = (stringToPair(x) for x in relations.split(' '))
|
||||||
|
return cls(relations)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fromDivisibilityPosetTo(cls, n):
|
||||||
|
pairs = set()
|
||||||
|
for dst in range(n):
|
||||||
|
pairs.add((dst, dst))
|
||||||
|
for src in range(1, dst):
|
||||||
|
if dst % src == 0:
|
||||||
|
pairs.add((src, dst))
|
||||||
|
return cls(pairs)
|
||||||
|
|
||||||
|
|
||||||
|
def isReflexive(self):
|
||||||
|
elements = set(list(sum(self.pairs, ())))
|
||||||
|
result = all((x,x) in self.pairs for x in elements)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
printc('Not reflexive, missing following pairs:', color='green')
|
||||||
|
missingPairs = [(x,x) for x in elements if (x,x) not in self.pairs]
|
||||||
|
print(f'\\[ {", ".join(pairToString(p) for p in missingPairs)} \\]')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def isSymmetric(self):
|
||||||
|
result = all((y,x) in self.pairs for x,y in self.pairs)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
printc('Not symmetric, missing following pairs:', color='green')
|
||||||
|
missingPairs = [(x,y) for x,y in self.pairs if (y,x) not in self.pairs]
|
||||||
|
print(f'\\[ {", ".join(pairToString(p) for p in missingPairs)} \\]')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def isAntiSymmetric(self):
|
||||||
|
result = not any((y,x) in self.pairs and y != x for x,y in self.pairs)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
printc('Not antisymmetric, following pairs are symmetric:', color='green')
|
||||||
|
symmetricPairs = [((x,y), (y,x)) for x,y in self.pairs if (y,x) in self.pairs and y > x]
|
||||||
|
print(f'\\[ {", ".join(f"{pairToString(p)} and {pairToString(q)}" for p,q in symmetricPairs)} \\]')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def isTransitive(self):
|
||||||
|
result = True
|
||||||
|
nonTransitivePairs = []
|
||||||
|
|
||||||
|
for x,y in self.pairs:
|
||||||
|
for z,w in self.pairs:
|
||||||
|
if not (y != z or ((x,w) in self.pairs)):
|
||||||
|
nonTransitivePairs.append(((x,y), (z,w)))
|
||||||
|
result = False
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
printc('Not transitive, following pairs are missing its transitive counterpart:', color='green')
|
||||||
|
print(f'\\[ {", ".join(f"{pairToString(p)} and {pairToString(q)} without {pairToString((p[0], q[1]))}" for p,q in nonTransitivePairs)} \\]')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def isEquivalenceRelation(self):
|
||||||
|
return self.isReflexive() and self.isSymmetric() and self.isTransitive()
|
||||||
|
|
||||||
|
def isPartialOrder(self):
|
||||||
|
return self.isReflexive() and self.isAntiSymmetric() and self.isTransitive()
|
||||||
|
|
||||||
|
def getHassePairs(self):
|
||||||
|
if not self.isPartialOrder():
|
||||||
|
printerr('This is not a partial order')
|
||||||
|
return
|
||||||
|
hassePairs = set()
|
||||||
|
for x1, y1 in self.pairs:
|
||||||
|
for x2, y2 in self.pairs:
|
||||||
|
if y1 == x2:
|
||||||
|
hassePairs.add((x1, y2))
|
||||||
|
return self.pairs - hassePairs
|
||||||
|
|
||||||
|
def latexifyHasseDiagram(self):
|
||||||
|
hasse = self.getHassePairs()
|
||||||
|
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});')
|
||||||
|
|
||||||
|
|
||||||
|
printc(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))
|
||||||
|
printc(f"Maximal elements: $\{{ {', '.join(str(e) for e in max_el)} \}}$" )
|
||||||
|
|
||||||
|
return '\n'.join(output)
|
||||||
|
|
||||||
|
def latexifyGraph(self):
|
||||||
|
if self.isEquivalenceRelation():
|
||||||
|
graphType = 'undirected'
|
||||||
|
pairs = [(x,y) for x,y in self.pairs if x != y]
|
||||||
|
else:
|
||||||
|
graphType = 'directed'
|
||||||
|
pairs = self.pairs
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def processFileContent(raw, template):
|
||||||
|
outputType, inp = raw.split('\n\n')
|
||||||
|
|
||||||
|
if inp.startsWith('divisibilityPosetTo'):
|
||||||
|
n = int(inp.split(' ')[1])
|
||||||
|
relation = Relation.fromDivisibilityPosetTo(n)
|
||||||
|
else:
|
||||||
|
relation = Relation.fromString(inp)
|
||||||
|
|
||||||
|
if outputType == 'proveEquivalence':
|
||||||
|
content = relation.isEquivalenceRelation()
|
||||||
|
elif outputType == 'provePoset':
|
||||||
|
content = relation.isPartialOrder()
|
||||||
|
elif outputType == 'hasseDiagram':
|
||||||
|
content = relation.latexifyHasseDiagram()
|
||||||
|
elif outputType == 'graph':
|
||||||
|
content = relation.latexifyGraph()
|
||||||
|
|
||||||
|
content = Relation.fromString(raw).latexifyHasseDiagram()
|
||||||
|
return template.replace("%CONTENT", content)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
inp = 'AA BB CC DD AB AC AD BC BD CD'
|
||||||
|
relations = [stringToPair(p) for p in inp.split(' ')]
|
||||||
|
# print(Relation(relations).isEquivalenceRelation())
|
||||||
|
print(Relation(relations).isPartialOrder())
|
||||||
|
print(Relation.fromDivisibilityPosetTo(30).isPartialOrder())
|
|
@ -1,9 +1,12 @@
|
||||||
from sys import argv
|
from sys import argv
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from common import printerr
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
except:
|
except:
|
||||||
print('Couldn\'t find tabulate. Do you have it installed?')
|
printerr('Couldn\'t find tabulate. Do you have it installed?')
|
||||||
|
|
||||||
|
|
||||||
def parseExpressionList(inputData):
|
def parseExpressionList(inputData):
|
||||||
|
@ -111,11 +114,8 @@ if __name__ == '__main__':
|
||||||
exps = parseExpressionList(file.read())
|
exps = parseExpressionList(file.read())
|
||||||
truthtable = generateTruthTable(exps)
|
truthtable = generateTruthTable(exps)
|
||||||
|
|
||||||
# try:
|
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
printTruthtable(exps, generateTruthTable(exps))
|
printTruthtable(exps, generateTruthTable(exps))
|
||||||
# except e:
|
|
||||||
# print(e)
|
|
||||||
|
|
||||||
content = latexify(exps, truthtable)
|
content = latexify(exps, truthtable)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
clear = '\033[0m'
|
||||||
|
colors = {
|
||||||
|
'red': '\033[31m',
|
||||||
|
'green': '\033[32m',
|
||||||
|
'yellow': '\033[33m',
|
||||||
|
'blue': '\033[34m',
|
||||||
|
'purple': '\033[35m',
|
||||||
|
'cyan': '\033[36m',
|
||||||
|
}
|
||||||
|
|
||||||
|
def printc(text, color='blue'):
|
||||||
|
print(f'{colors[color]}{text}{clear}')
|
||||||
|
|
||||||
|
def printerr(text):
|
||||||
|
print(f'\033[31;5m[ERROR] {text}{clear}')
|
|
@ -5,9 +5,8 @@ import FSA
|
||||||
import Graph
|
import Graph
|
||||||
import Hasse
|
import Hasse
|
||||||
import Truthtable
|
import Truthtable
|
||||||
|
import Relations
|
||||||
def printred(text):
|
from common import printerr
|
||||||
print(f'\033[31m{text}\033[0m')
|
|
||||||
|
|
||||||
def fetchContentType(content):
|
def fetchContentType(content):
|
||||||
new_content = content.split('\n')
|
new_content = content.split('\n')
|
||||||
|
@ -25,10 +24,12 @@ def processContent(content):
|
||||||
result = Graph.processFileContent('toGraph\n\n' + content, template.read())
|
result = Graph.processFileContent('toGraph\n\n' + content, template.read())
|
||||||
elif contentType == 'Matrix':
|
elif contentType == 'Matrix':
|
||||||
result = Graph.processFileContent('toMatrix\n\n' + content, template.read())
|
result = Graph.processFileContent('toMatrix\n\n' + content, template.read())
|
||||||
|
elif contentType == 'Relations':
|
||||||
|
result = Relations.processFileContent(content, template.read())
|
||||||
elif contentType == 'Truthtable':
|
elif contentType == 'Truthtable':
|
||||||
result = Truthtable.processFileContent(content, template.read())
|
result = Truthtable.processFileContent(content, template.read())
|
||||||
else:
|
else:
|
||||||
print('DIDN\'T RECOGNIZE FILE TYPE')
|
printerr('DIDN\'T RECOGNIZE FILE TYPE')
|
||||||
exit(1)
|
exit(1)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Relations
|
||||||
|
graph
|
||||||
|
|
||||||
|
AA BB CC DD EE AC CA AE EA CE EC BD DB
|
|
@ -1,2 +1,4 @@
|
||||||
# Hasse
|
# Relations
|
||||||
|
hasseDiagram
|
||||||
|
|
||||||
ab ac ad ae bc ed ec
|
ab ac ad ae bc ed ec
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Relations
|
||||||
|
proveEquivalence
|
||||||
|
|
||||||
|
AA BB CC DD EE AC CA AE EA CE EC BD DB
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Relations
|
||||||
|
provePoset
|
||||||
|
|
||||||
|
AA BB CC DD AB AC AD BC CD BD
|
Loading…
Reference in New Issue