Created
August 21, 2015 14:13
-
-
Save knkillname/5a789cfd0011a6255ea7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Author: Mario Abarca (knkillname) | |
## Email: asma@uaem.mx | |
## Date: 25 Feb 2015 | |
## Language: Python 3 | |
## | |
## Summary: A class representing bigraph objects given by a quasi-Cartan | |
## Matrix. Includes elementary operations, csv formating, and ploting. | |
from array import array | |
from os.path import splitext | |
from itertools import chain | |
from math import pi, sqrt, sin, cos | |
from cmath import rect | |
from random import uniform, choice, getrandbits, randint | |
from collections import deque | |
from tkinter import * | |
from tkinter import ttk | |
class bigraph: | |
__slots__ = ('_adj', '_vert', '_idx') | |
def __init__(self): | |
self._adj = [] | |
self._vert = [] #vert[i]: name of vertex i | |
self._idx = dict() #idx[v]: index of vertex v | |
def __len__(self): | |
return len(self._adj) | |
@property | |
def adj(self): | |
return self._adj | |
def vertices(self): | |
return iter(self._vert) | |
def _edges(self): | |
A = self._adj | |
for i in range(len(A) - 1): | |
for j in range(i + 1, len(A)): | |
if i != j and A[i][j] != 0: | |
dotted = (A[i][j] > 0) | |
direction = abs(A[j][i]) - abs(A[i][j]) | |
if direction > 0: | |
e = '$>' | |
elif direction == 0: | |
e = '$$' | |
else: e = '<$' | |
if dotted: | |
e = e.replace('$', '.') | |
else: e = e.replace('$', '-') | |
yield (i, e, j) | |
def edges(self): | |
for (i, e, j) in self._edges(): | |
yield (self._vert[i], e, self._vert[j]) | |
def _add_vertex(self, name): | |
n = len(self._adj) | |
self._idx[name] = n | |
self._vert.append(name) | |
for row in self._adj: | |
row.append(0) | |
self._adj.append(array('b', (0 for k in range(n + 1)))) | |
self._adj[n][n] = 2 | |
return n | |
def _add_edge(self, u, v, e): | |
i, j = self._idx[u], self._idx[v] | |
if e == '--': | |
self._adj[i][j] -= 1 | |
self._adj[j][i] -= 1 | |
elif e == '->': | |
self._adj[i][j] -= 1 | |
self._adj[j][i] -= 2 | |
elif e == '<-': | |
self._adj[i][j] -= 2 | |
self._adj[j][i] -= 1 | |
elif e == '..': | |
self._adj[i][j] += 1 | |
self._adj[j][i] += 1 | |
elif e == '.>': | |
self._adj[i][j] += 1 | |
self._adj[j][i] += 2 | |
elif e == '<.': | |
self._adj[i][j] += 2 | |
self._adj[j][i] += 1 | |
else: raise ValueError | |
def add(self, path): | |
sentinel, item = object(), iter(path) | |
u = next(item) | |
if u not in self._idx: self._add_vertex(u) | |
while True: | |
e = next(item, sentinel) | |
if e == sentinel: | |
break | |
if not isinstance(e, str): | |
raise TypeError | |
v = next(item) | |
if u == v: raise ValueError | |
if v not in self._idx: self._add_vertex(v) | |
self._add_edge(u, v, e) | |
u = v | |
def delete(self, u): | |
i = self._idx[u] | |
del self._adj[i] | |
for row in self._adj: | |
del row[i] | |
del self._vert[i] | |
for (j, v) in enumerate(self._vert): | |
self._idx[v] = j | |
del self._idx[u] | |
def shrink(self, X, v): | |
if v not in self._idx: | |
self._add_vertex(v) | |
for u in X: | |
if u == v: continue | |
i = self._idx[u] | |
j = self._idx[v] | |
for (k, w) in enumerate(self._adj[i]): | |
if k != j and w != 0: | |
self._adj[k][j] += self._adj[k][i] | |
self._adj[j][k] += self._adj[i][k] | |
self.delete(u) | |
def neighbors(self, u): | |
i = self._idx[u] | |
for (j, w) in enumerate(self._adj[i]): | |
if w != 0: | |
yield self._vert[j] | |
def __str__(self, sort = False): | |
A, n, idx, vert = self._adj, len(self._adj), self._idx, self._vert | |
if n*n > 0: | |
I = list(idx[v] for v in sorted(self._idx)) if sort else range(n) | |
N = [str(vert[i]) for i in I] | |
B = [[str(A[i][j]) for j in I] for i in I] | |
p = [max(max(len(B[i][j]) for i in I), len(N[j])) for j in I] | |
N = [N[j].center(p[j]) for j in I] | |
B = [[B[i][j].center(p[j]) for j in I] for i in I] | |
B = [' '.join(B[i]) for i in I] | |
N = ' ' + ' '.join(N) | |
else: return '[]' | |
if n > 1: | |
B[0] = ''.join(['┌', B[0] ,'┐']) | |
B[1 : n - 1] = [''.join(['│', B[i] ,'│']) for i in range(1, n - 1)] | |
B[n - 1] = ''.join(['└', B[n - 1] ,'┘']) | |
return '\n'.join([N, '\n'.join(row for row in B)]) | |
else: return '\n'.join([N, ''.join(['[', B[0] ,']'])]) | |
def _embed(self, pos = None, temp = 1.0, steps = None): | |
#Uses Fruchterman-Reingold force embedder | |
n = len(self._adj) | |
if pos == None: | |
pos = [rect(temp/2, uniform(-pi, pi)) for u in range(n)] | |
if steps == None: | |
steps = n*(n - 1) + 1 | |
cool = temp/steps | |
for i in range(steps): | |
disp = [complex(0.0, 0.0) for v in range(n)] | |
for u in range(n - 1): | |
for v in range(u + 1, n): | |
D = pos[v] - pos[u] | |
rf = D/(D.real**2 + D.imag**2) | |
disp[v] += rf | |
disp[u] -= rf | |
if self._adj[u][v] != 0: | |
D = pos[v] - pos[u] | |
af = abs(D)*D | |
disp[u] += af | |
disp[v] -= af | |
for v in range(n): | |
pos[v] += (disp[v]/abs(disp[v]))*min(abs(disp[v]), temp) | |
temp -= cool | |
return pos | |
def embedding(self, start_pos = None, raw_output = False, | |
temp = 1.0, steps = None): | |
idx = self._idx | |
if len(self._adj) == 0: return dict() | |
if start_pos != None: | |
pos = [None]*len(self._adj) | |
for (v, (x, y)) in start_pos.items(): | |
pos[idx[v]] = complex(x, y) | |
start_pos = pos | |
pos = self._embed(start_pos, temp, steps) | |
if raw_output: | |
return pos | |
return {self._vert[i]:(p.real, p.imag) for (i, p) in enumerate(pos)} | |
def _edge_partition(self): | |
#Separates the edges in four types: 0. Nondirected solid edges | |
#1. Directed solid edges 2. Nondirected dotted edges and | |
#3. Directed dotted edges | |
A = self._adj | |
n = len(A) | |
edges = [[], [], [], []] | |
for i in range(n - 1): | |
for j in range(i + 1, n): | |
if A[i][j] == 0: continue | |
edge_type = 2*int(A[i][j] > 0) + int(A[i][j] != A[j][i]) | |
if abs(A[i][j]) < abs(A[j][i]): | |
(u, v) = (i, j) | |
else: (u, v) = (j, i) | |
edges[edge_type].append((u, v)) | |
return edges | |
def tex(self, edge_length = 1.0, pos = None): | |
def coords(z): | |
return (round(z.real, 2), round(z.imag, 2)) | |
V = self._vert | |
n = len(V) | |
s = ' \\node (v{}) at {} {{{}}};' | |
if pos == None: | |
pos = self._embed() | |
nodes = '\n'.join(s.format(i, coords(pos[i]), V[i])\ | |
for i in range(n)) | |
else: | |
pos = [pos[v] for v in self._vert] | |
nodes = '\n'.join(s.format(i, pos[i], V[i]) for i in range(n)) | |
edges = self._edge_partition() | |
for t in range(4): | |
edges[t] = ', '.join('v{}/v{}'.format(u, v) for (u, v) in edges[t]) | |
return '''\\begin{{tikzpicture}}[scale = {0}, every node/.style={{circle, inner sep=1pt}}] | |
{1} | |
\\foreach \\from/\\to in {{{2}}} | |
\\draw (\\from) -- (\\to); | |
\\foreach \\from/\\to in {{{3}}} | |
\\draw[->] (\\from) -- (\\to); | |
\\foreach \\from/\\to in {{{4}}} | |
\\draw[dotted] (\\from) -- (\\to); | |
\\foreach \\from/\\to in {{{5}}} | |
\\draw[->, dotted] (\\from) -- (\\to); | |
\\end{{tikzpicture}}'''.format(edge_length, nodes, *edges) | |
@staticmethod | |
def load(file_name): | |
(path, ext) = splitext(file_name) | |
if not ext: ext = '.csv' | |
file = open(path + ext) | |
vert = [eval(item) for item in (file.readline().strip()).split(',')] | |
adj = file.readlines() | |
file.close() | |
n = len(vert) | |
if len(adj) != n: | |
raise ValueError('File does not contain a valid bigraph') | |
for k in range(n): | |
adj[k] = array('b', map(int, (adj[k].strip()).split(','))) | |
if len(adj[k]) != n or adj[k][k] != 2: | |
raise ValueError('File does not contain a valid bigraph') | |
G = bigraph() | |
G._adj = adj | |
G._vert = vert | |
G._idx = {u:i for (i, u) in enumerate(vert)} | |
return G | |
def save(self, file_name): | |
lines = [','.join(str(item) for item in row) for row in self._adj] | |
(path, ext) = splitext(file_name) | |
if not ext: ext = '.csv' | |
file = open(path + ext, 'w') | |
file.write(','.join(map(repr, self._vert))) | |
file.write('\n') | |
file.write('\n'.join(lines)) | |
file.close() | |
def plot(self, typeface = 'times', size = 14, border = 8, thickness = 1, | |
pos = None): | |
def coords(z): | |
return (z.real, z.imag) | |
def redraw(event): | |
canvas.delete('all') | |
k = min((event.width - blft - brgt)/w, | |
(event.height - btop - bbot)/h) | |
p = [k*z + b for z in pos] | |
for (i, e, j) in elist: | |
x1, y1 = coords(p[i]) | |
x2, y2 = coords(p[j]) | |
if '-' in e: | |
canvas.create_line(x1, y1, x2, y2) | |
else: | |
canvas.create_line(x1, y1, x2, y2, dash = (2,)) | |
if ('>' in e) or ('<' in e): | |
if '<' in e: i, j = j, i | |
arg = p[i] - p[j] | |
arg = arg/abs(arg) | |
ort = complex(arg.imag, -arg.real) | |
ti0 = p[j] + rad[j]*arg | |
ti1 = ti0 + (0.5*size)*arg + (0.25*size)*ort | |
ti2 = ti0 + (0.25*size)*arg | |
ti3 = ti0 + (0.5*size)*arg - (0.25*size)*ort | |
x0, y0 = coords(ti0) | |
x1, y1 = coords(ti1) | |
x2, y2 = coords(ti2) | |
x3, y3 = coords(ti3) | |
canvas.create_polygon(x0, y0, x1, y1, x2, y2, x3, y3, | |
fill = 'black', outline = '') | |
for i in range(n): | |
x, y = coords(p[i]) | |
canvas.create_oval(x - rad[i], y - rad[i], | |
x + rad[i], y + rad[i], | |
fill = 'lightgray', outline = '') | |
canvas.create_text(x, y, text = vlist[i], | |
font = (typeface, size)) | |
if len(self._adj) == 0: raise RuntimeError('Nothing to plot!') | |
if pos == None: | |
pos = self._embed() | |
else: | |
C = lambda z: complex(z[0], z[1]) | |
pos = [C(pos[v]) for v in self._vert] | |
vlist = list(self._vert) | |
elist = list(self._edges()) | |
n, m = len(vlist), len(elist) | |
ilft, irgt, itop, ibot = 0, 0, 0, 0 | |
for i in range(n): | |
if pos[i].real < pos[ilft].real: | |
ilft = i | |
if pos[i].real > pos[irgt].real: | |
irgt = i | |
if pos[i].imag < pos[itop].imag: | |
itop = i | |
if pos[i].imag > pos[ibot].imag: | |
ibot = i | |
d = complex(pos[ilft].real, pos[itop].imag) | |
for i in range(n): | |
pos[i] -= d | |
w = pos[irgt].real | |
h = pos[ibot].imag | |
root = Tk() | |
root.title('Plot') | |
root.columnconfigure(0, weight = 1) | |
root.rowconfigure(0, weight = 1) | |
canvas = Canvas(root, background = 'white') | |
rad = [0.0 for i in range(n)] | |
aux = canvas.create_text(0, 0, fill = 'white', font = (typeface, size)) | |
for i in range(n): | |
canvas.itemconfig(aux, text = vlist[i]) | |
x1, y1, x2, y2 = canvas.bbox(aux) | |
rad[i] = 0.5*sqrt((x2 - x1)**2 + (y2 - y1)**2) | |
canvas.delete(aux) | |
del aux | |
blft, btop, brgt, bbot = (rad[i] + border \ | |
for i in (ilft, itop, irgt, ibot)) | |
b = complex(blft, btop) | |
k = 5*size | |
canvas.config(width = k*w + blft + brgt, height = k*h + btop + bbot) | |
canvas.grid(column = 0, row = 0, sticky=(N, W, E, S)) | |
canvas.bind('<Configure>', redraw) | |
root.bind('<Return>', lambda e: root.destroy()) | |
root.mainloop() | |
def _flation(self, s, r): | |
A = self._adj | |
V = range(len(A)) | |
row = [-A[r][s]*A[s][k] for k in V] | |
col = [-A[s][r]*A[k][s] for k in V] | |
A[r][r] += A[s][s]*A[s][r]*A[r][s] | |
for k in V: | |
A[r][k] += row[k] | |
A[k][r] += col[k] | |
def flation(self, s, r): | |
self._flation(self._idx[s], self._idx[r]) | |
def inversion(self, r): | |
A, r = self._adj, self._idx[r] | |
n = len(A) | |
for k in range(n): | |
A[k][r] *= -1 | |
A[r][k] *= -1 | |
def permutation(self, s, r): | |
i, j = self._idx[s], self._idx[r] | |
self._idx[s], self._idx[r] = j, i | |
self._vert[i], self._vert[j] = r, s | |
def frame(self): | |
F = bigraph() | |
F._vert = self._vert[:] | |
F._idx = self._idx.copy() | |
F._adj = [array('b', (-(a % 2) for a in row)) for row in self._adj] | |
return F | |
@staticmethod | |
def finite_A(n): | |
B = bigraph() | |
path = lambda i: '--' if i % 2 else i//2 + 1 | |
B.add(path(i) for i in range(2*n - 1)) | |
return B | |
@staticmethod | |
def finite_B(n): | |
B = bigraph.finite_A(n - 1) | |
B.add([n - 1, '->', n]) | |
return B | |
@staticmethod | |
def finite_C(n): | |
B = bigraph.finite_A(n - 1) | |
B.add([n - 1, '<-', n]) | |
return B | |
@staticmethod | |
def finite_D(n): | |
B = bigraph.finite_A(n) | |
B.add([2, '..', 1, '--', 3]) | |
return B | |
@staticmethod | |
def finite_E(n): | |
B = bigraph.finite_A(n) | |
B.add([2, '..', 1, '--', 4]) | |
return B | |
@staticmethod | |
def finite_F(n): | |
B = bigraph.finite_A(n) | |
B.add([3, '..', 2, '->', 3]) | |
return B | |
def reduce(self, plot = False): | |
A, n, v = self._adj, len(self._adj), self._vert | |
while True: | |
dotted = [(i, j) for (i, e, j) in self._edges() if A[i][j] > 0] | |
if not dotted: break | |
(s, r) = choice(dotted) | |
if bool(getrandbits(1)): | |
s, r = r, s | |
self._flation(s, r) | |
yield v[s], v[r] | |
def treeify(self): | |
A, n, vname = self._adj, len(self._adj), self._vert | |
V = [i for (i, u) in sorted(enumerate(self._vert), | |
key = lambda t: t[1])] | |
def dfs_chrodless_cycle(s): | |
nonlocal A | |
nonlocal V | |
nonlocal n | |
visited = [False for v in V] | |
parent = [None for v in V] | |
dist = [float('inf') for v in V] | |
visited[s], dist[s] = True, 0 | |
Q = deque([s]) | |
flag = False | |
while len(Q) > 0: | |
u = Q.popleft() | |
for v in V: | |
if bool(A[u][v] % 2) and u != v: | |
if not visited[v]: | |
visited[v] = True | |
parent[v] = u | |
dist[v] = dist[u] + 1 | |
Q.append(v) | |
elif parent[u] != v: | |
flag = True | |
break | |
if flag: break | |
if not flag: return None | |
P = deque() | |
if dist[v] > dist[u]: | |
P.append(v) | |
v = parent[v] | |
while u != v: | |
P.appendleft(u) | |
P.append(v) | |
u, v = parent[u], parent[v] | |
P.appendleft(u) | |
return list(P) | |
r = V[0] | |
while True: | |
p = dfs_chrodless_cycle(r) | |
if p is None: break | |
for k in range(1, len(p) - 1): | |
self._flation(p[k], p[k + 1]) | |
yield list(vname[u] for u in p[1:]) | |
if __name__ == '__main__': | |
G = bigraph() | |
G.add([1, '..', 2, '--', 3, '.>', 4, '<-' ,2]) | |
for row in G._adj: | |
print(list(row)) | |
print(G.tex()) | |
for e in G.edges(): | |
print(e) | |
G.plot(size = 12) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Author: Mario Abarca (knkillname) | |
## Email: asma@uaem.mx | |
## Date: 18 Mar 2015 | |
## Language: Python 3 | |
## | |
## Summary: A simple command-line utility for interacting with bigraphs. | |
import re | |
import os | |
from cmd import Cmd | |
from bigraph import bigraph | |
from collections import namedtuple | |
token = namedtuple('token', ['typ', 'val']) | |
class arg_parser: | |
tokens = {'int': r'\d+', | |
'edge': r'(\-\-)|(\->)|(<\-)|(\.\.)|(\.>)|(<\.)', | |
'id': r'[A-F]', | |
'skip': r'\s+'} | |
def __init__(self): | |
tok_rex = '|'.join('(?P<{}>{})'.format(t, r) \ | |
for (t, r) in self.tokens.items()) | |
self.token_match = re.compile(tok_rex).match | |
self.whitespace = re.compile('\s+') | |
def tokenize(self, arg): | |
mo = self.token_match(arg) | |
pos = 0 | |
while mo is not None: | |
typ = mo.lastgroup | |
if typ != 'skip': | |
yield token(typ, mo.group(typ)) | |
pos = mo.end() | |
mo = self.token_match(arg, pos) | |
if pos != len(arg): | |
raise RuntimeError('Unexpected character') | |
def intseq(self, arg): | |
for tok in self.tokenize(arg): | |
if tok.typ != 'int': raise RuntimeError('Unexpected token') | |
yield int(tok.val) | |
def path(self, arg): | |
vert = True | |
for tok in self.tokenize(arg): | |
if vert and tok.typ == 'int': | |
yield int(tok.val) | |
elif not vert and tok.typ == 'edge': | |
yield tok.val | |
else: raise RuntimeError('Unexpected token') | |
vert = not vert | |
if vert: raise RuntimeError('Invalid sintax') | |
def splitargs(self, args): | |
return self.whitespace.split(args.strip()) | |
def cartype(self, args): | |
toks = list(self.tokenize(args)) | |
if len(toks) != 2 or toks[0].typ != 'id' or toks[1].typ != 'int': | |
raise RuntimeError('Unexpected token') | |
return (toks[0].val, int(toks[1].val)) | |
class interactive(Cmd): | |
intro = 'interactive.py 3.2 Type «?» for help.' | |
prompt = '> ' | |
nosintax = '* Unknown sintax: {}' | |
def check_graphical(self): | |
V = list(self.B.vertices()) | |
A = self.B.adj | |
n = len(A) | |
self.graficable = True | |
for u in range(1, n): | |
for v in range(u): | |
if A[u][v]*A[v][u] > 4: | |
print('Multiple edges at {}──{}.'.format(V[u], V[v])) | |
self.graficable = False | |
if (A[u][v] == 0) != (A[v][u] == 0): | |
print('Undefined edge at {}──{}.'.format(V[u], V[v])) | |
self.graficable = False | |
def __init__(self): | |
super().__init__() | |
self.B = bigraph() | |
self.pos = None | |
self.parse = arg_parser() | |
def do_neighbors(self, args): | |
'''Sintax: neighbors v | |
Shows the neighbors of vertex v in the current bigraph.''' | |
try: | |
u = int(args.strip()) | |
except RuntimeError: return self.default('neighbors', args) | |
if u in self.B.vertices(): | |
print(' '.join(map(str, self.B.neighbors(u)))) | |
else: print('{} does not belong to this bigraph'.format(u)) | |
def do_new(self, args): | |
'''Sintaxis: new [id] | |
Loads an empty bigraph. Optional argument id can take values A, B, C, D, E or F | |
followed by a positive integer. Examples: | |
new → loads a new, empty bigraph | |
new E6 → loads the Dynkin graph E6''' | |
if args: | |
try: | |
args = self.parse.cartype(args) | |
except: return self.default('new', args) | |
cons = {'A':bigraph.finite_A, | |
'B':bigraph.finite_B, | |
'C':bigraph.finite_C, | |
'D':bigraph.finite_D, | |
'E':bigraph.finite_E, | |
'F':bigraph.finite_F} | |
self.B = cons[args[0]](args[1]) | |
else: self.B = bigraph() | |
self.pos = None | |
self.graficable = True | |
def do_quit(self, args): | |
'''Sintax: quit''' | |
if args == '': | |
return True | |
else: self.default('quit', args) | |
def do_tex(self, args): | |
'''Sintax: tex | |
Prints out a LaTeX listing which uses TikZ package to draw the bigraph''' | |
print(self.B.tex(pos = self.pos)) | |
def do_load(self, args): | |
'''Sintax: load file | |
Loads a given csv file (no extension needed) as the quasi-Cartan matrix | |
representing a bigraph. Example: load ejemplo''' | |
try: | |
self.B = bigraph.load(args) | |
self.pos = None | |
except: print('Error al abrir {}'.format(repr(args))) | |
def do_save(self, args): | |
'''Sintaxis: save file | |
Saves the current bigraph. | |
Example: save thisbigraph''' | |
try: | |
self.B.save(args) | |
except: print('Error al guardar {}'.format(repr(args))) | |
def do_plot(self, args): | |
'''Sintax: plot [frame] | |
Shows the current bigraph on screen. If used with "frame" the plot draws | |
dotted edges as solid ones.''' | |
if self.graficable: | |
if self.B.vertices(): | |
args = self.parse.splitargs(args) | |
self.pos = self.B.embedding(start_pos = self.pos) | |
if args == ['frame']: | |
self.B.frame().plot(pos = self.pos) | |
else: self.B.plot(pos = self.pos) | |
else: print('Nothing to graph.') | |
else: print('The current matrix is not graphical.') | |
def do_adj(self, args): | |
'''Sintax: adj [maxima|python] | |
Shows the quasi-Cartan (adjacency matrix) of the current bigraph.''' | |
if not args: | |
print(self.B) | |
else: | |
adj = self.B.adj | |
if args == 'maxima': | |
print('matrix({})'.format(', '.join(str(list(row)) for row in adj))) | |
elif args == 'python': | |
print(adj) | |
def do_T(self, args): | |
'''Sintax: T v₁ v₂ v₃ … vₖ | |
Applies the flation transformation from v₁ to v₂, from v₂ to v₃, etc.''' | |
try: | |
v = list(self.parse.intseq(args)) | |
except RuntimeError: v = [] | |
if len(v) < 2: | |
self.default('T', args) | |
else: | |
B = self.B | |
if any(u not in self.B.vertices() for u in v): | |
print('All vertices must belong to the bigraph.') | |
return False | |
for k in range(len(v) - 1): | |
B.flation(v[k], v[k + 1]) | |
self.check_graphical() | |
def do_I(self, args): | |
'''Sintax: I v₁ v₂ v₃ … vₖ | |
Applies the sign-inversion operation over v₁, v₂, v₃, … vₖ.''' | |
try: | |
v = list(self.parse.intseq(args)) | |
except RuntimeError: v = [] | |
if len(v) < 1: | |
self.default('I', args) | |
else: | |
if any(u not in self.B.vertices() for u in v): | |
print('All vertices must belong to the bigraph.') | |
return False | |
B = self.B | |
for u in v: | |
B.inversion(u) | |
def do_P(self, args): | |
'''Sintax: P v₁ v₂ | |
Intercchanges the labels of vertices v₁ and v₂.''' | |
try: | |
u, v = self.parse.intseq(args) | |
except: return self.default('P', args) | |
if not {u, v} <= self.B.vertices(): | |
print('The vertices must belong to the bigraph.') | |
return False | |
else: self.B.permutation(u, v) | |
def do_S(self, args): | |
'''Sintax: S v₁ v₂ v₃ … vₖ | |
Shrinks the subgraph given by the vertices v₁ v₂ v₃ … vₖ into a single vertex | |
with label vₖ.''' | |
try: | |
v = list(self.parse.intseq(args)) | |
except RuntimeError: v = [] | |
if len(v) < 2: | |
self.default('S', args) | |
else: | |
if any(u not in self.B.vertices() for u in v): | |
print('All vertices must belong to the bigraph.') | |
else: | |
self.B.shrink(v, v[-1]) | |
if self.pos is not None: | |
for k in range(len(v) - 1): | |
del self.pos[v[k]] | |
self.check_graphical() | |
def do_add(self, args): | |
'''Sintax: add v₀ e₁ v₁ e₂ v₂ e₃ v₃ … eₖ vₖ | |
Adds a path to the bigraph. vertices must be natural numbers and y the edges | |
can be of four types: | |
-- : solid edge | |
.. : dotted edge | |
-> : solid arc (also <-) | |
.> : doted arc (also <.) | |
Example: add 1--2..3.>4<-5''' | |
if args: | |
try: | |
path = list(self.parse.path(args)) | |
except RuntimeError: return self.default('add', args) | |
self.B.add(path) | |
self.pos = None | |
self.check_graphical() | |
else: | |
print('Nothing to add.') | |
def do_del(self, args): | |
'''Sintax: del v₁ v₂ v₃ … vₖ | |
Deletes the vertices v₁, v₂, v₃, …, vₖ from the bigraph.''' | |
try: | |
u = int(args.strip()) | |
except: return self.default('del', args) | |
if u in self.B.vertices(): | |
self.B.delete(u) | |
del self.pos[u] | |
else: print('{} does not belong to the bigraph.'.format(u)) | |
def default(self, *args): | |
print(self.nosintax.format(' '.join(args))) | |
def do_reduce(self, args): | |
'''Sintax: reduce [plot] [adj] [tex] | |
Aplies the inflations method to the current bigraph.''' | |
flags = frozenset(self.parse.splitargs(args)) | |
if not flags <= frozenset(['plot', 'tex', 'adj', '']): | |
return self.default('reduce', args) | |
bplot = 'plot' in flags | |
btex = 'tex' in flags | |
badj = 'adj' in flags | |
T = iter(self.B.reduce()) | |
while True: | |
if badj: self.do_adj('') | |
if bplot: self.do_plot('') | |
if btex: self.do_tex('') | |
edge = next(T, None) | |
if edge == None: break | |
print('> T {} {}'.format(*edge)) | |
self.check_graphical() | |
def do_treeify(self, args): | |
'''Sintax: treeify [plot] [adj] [tex] | |
Applies an heuristic flations method which tries to compute the tree form of | |
the current bigraph.''' | |
flags = frozenset(self.parse.splitargs(args)) | |
if not flags <= frozenset(['plot', 'tex', 'adj', '']): | |
return self.default('treeify', args) | |
bplot = 'plot' in flags | |
btex = 'tex' in flags | |
badj = 'adj' in flags | |
T = iter(self.B.treeify()) | |
while True: | |
if badj: self.do_adj('') | |
if bplot: self.do_plot('') | |
if btex: self.do_tex('') | |
path = next(T, None) | |
if path == None: break | |
print('> T ' + ' '.join(map(str, path))) | |
self.check_graphical() | |
if __name__ == '__main__': | |
os.system('clear') | |
interactive().cmdloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment