def MatrixCharpoly(coefficients): """ INPUT: - ``coefficients`` -- an array with n + 1, where the first entry is 1 OUTPUT: - a matrix A such that det(1 - t A) = R[](coefficients) EXAMPLES: sage: list(reversed(yellow.MatrixCharpoly([1,2,3]).characteristic_polynomial().list())) == [1,2,3] True TESTS: sage: test_pass = True sage: for i in range(10): ....: cf = [1] + [ZZ.random_element() for _ in range(randint(1,10))]; ....: test_pass = test_pass and (list(reversed(MatrixCharpoly(cf).characteristic_polynomial().list())) == cf) sage: print test_pass True """ assert coefficients[0] == 1 n = len(coefficients) - 1 M = Matrix(1, n - 1).stack(identity_matrix(n - 1, n - 1)) M = M.augment(-vector(reversed(coefficients[1:]))) return M
def pade_linalg(input_series, m): ring = input_series.base_ring() polyring = input_series.parent()._poly_ring() an = vector(ring, input_series.padded_list()) minus_an = -an; N = len(an) - 1 n = N - m if n < 0: raise ValueError("the precision of the series is not large enough") Akj = Matrix(ring, N + 1, n + 1); for i in range(min(N + 1, n + 1)): Akj[i, i] = 1; Bkj = Matrix(ring, N + 1, m); for row in range(1, m+1): Bkj[row,:row] = minus_an[:row][::-1] for row in range(m+1, N+1): Bkj[row,:] = minus_an[row-m:row][::-1] C = Akj.augment(Bkj); pq = C.solve_right(an).list() p = pq[:n+1] q = [1] + pq[n+1:] return polyring(p), polyring(q)
class StrataGraph(object): R = PolynomialRing(ZZ, "X", 1, order='lex') Xvar = R.gen() def __init__(self, M=None, genus_list=None): #print genus_list if M: self.M = copy(M) elif genus_list: self.M = Matrix(StrataGraph.R, len(genus_list) + 1, 1, [-1] + genus_list) else: self.M = Matrix(StrataGraph.R, 1, 1, -1) def __repr__(self): """ Drew added this. """ name = self.nice_name() if name == None: return repr(self.nice_matrix()) else: return name def num_vertices(self): return self.M.nrows() - 1 def num_edges(self): return self.M.ncols() - 1 def h1(self): return self.M.ncols() - self.M.nrows() + 1 def add_vertex(self, g): self.M = self.M.stack(Matrix(1, self.M.ncols())) self.M[-1, 0] = g def add_edge(self, i1, i2, marking=0): self.M = self.M.augment(Matrix(self.M.nrows(), 1)) self.M[0, -1] = marking if i1 > 0: self.M[i1, -1] += 1 if i2 > 0: self.M[i2, -1] += 1 def del_vertex(self, i): self.M = self.M[:i].stack(self.M[(i + 1):]) def del_edge(self, i): self.M = self.M[0:, :i].augment(self.M[0:, (i + 1):]) def compute_degree_vec(self): self.degree_vec = [ sum(self.M[i, j][0] for j in range(1, self.M.ncols())) for i in range(1, self.M.nrows()) ] def degree(self, i): return self.degree_vec[i - 1] def split_vertex(self, i, row1, row2): self.M = self.M.stack(Matrix(2, self.M.ncols(), row1 + row2)) self.add_edge(self.M.nrows() - 2, self.M.nrows() - 1) self.del_vertex(i) def compute_parity_vec_original(self): X = StrataGraph.Xvar self.parity_vec = [ (ZZ(1 + self.M[i, 0][0] + sum(self.M[i, k][1] for k in range(1, self.M.ncols())) + sum(self.M[i, k][2] for k in range(1, self.M.ncols())) + self.M[i, 0].derivative(X).substitute(X=1)) % 2) for i in range(1, self.M.nrows()) ] def compute_parity_vec(self): self.parity_vec = [ (ZZ(1 + self.M[i, 0][0] + sum(self.M[i, k][1] for k in range(1, self.M.ncols())) + sum(self.M[i, k][2] for k in range(1, self.M.ncols())) + self.last_parity_summand(i)) % 2) for i in range(1, self.M.nrows()) ] def last_parity_summand(self, i): return sum( (expon[0] * coef for expon, coef in self.M[i, 0].dict().items())) def parity(self, i): return self.parity_vec[i - 1] def replace_vertex_with_graph(self, i, G): X = StrataGraph.Xvar nv = self.num_vertices() ne = self.num_edges() #i should have degree d, there should be no classes near i, and G should have markings 1,...,d and genus equal to the genus of i hedge_list = [] for k in range(1, self.M.ncols()): for j in range(ZZ(self.M[i, k])): hedge_list.append(k) self.del_vertex(i) for j in range(G.num_edges() - len(hedge_list)): self.add_edge(0, 0) for j in range(G.num_vertices()): self.add_vertex(G.M[j + 1, 0]) col = ne + 1 for k in range(1, G.M.ncols()): if G.M[0, k] > 0: mark = ZZ(G.M[0, k]) for j in range(G.num_vertices()): if self.M[nv + j, hedge_list[mark - 1]] == 0: self.M[nv + j, hedge_list[mark - 1]] = G.M[j + 1, k] elif G.M[j + 1, k] != 0: a = self.M[nv + j, hedge_list[mark - 1]][1] b = G.M[j + 1, k][1] self.M[nv + j, hedge_list[mark - 1]] = 2 + max(a, b) * X + min( a, b) * X**2 else: for j in range(G.num_vertices()): self.M[nv + j, col] = G.M[j + 1, k] col += 1 def compute_invariant(self): self.compute_parity_vec() self.compute_degree_vec() nr, nc = self.M.nrows(), self.M.ncols() self.invariant = [[self.M[i, 0], [], [], [[] for j in range(1, nr)]] for i in range(1, nr)] for k in range(1, nc): L = [i for i in range(1, nr) if self.M[i, k] != 0] if len(L) == 1: if self.M[0, k] != 0: self.invariant[L[0] - 1][2].append( [self.M[0, k], self.M[L[0], k]]) else: self.invariant[L[0] - 1][1].append(self.M[L[0], k]) else: self.invariant[L[0] - 1][3][L[1] - 1].append( [self.M[L[0], k], self.M[L[1], k]]) self.invariant[L[1] - 1][3][L[0] - 1].append( [self.M[L[1], k], self.M[L[0], k]]) for i in range(1, nr): self.invariant[i - 1][3] = [ term for term in self.invariant[i - 1][3] if len(term) > 0 ] for term in self.invariant[i - 1][3]: term.sort() self.invariant[i - 1][3].sort() self.invariant[i - 1][2].sort() self.invariant[i - 1][1].sort() vertex_invariants = [[i, self.invariant[i - 1]] for i in range(1, nr)] self.invariant.sort() vertex_invariants.sort(key=lambda x: x[1]) self.vertex_groupings = [] for i in range(nr - 1): if i == 0 or vertex_invariants[i][1] != vertex_invariants[i - 1][1]: self.vertex_groupings.append([]) self.vertex_groupings[-1].append(vertex_invariants[i][0]) #Drew added this self.invariant = tupleit(self.invariant) self.hash = hash(self.invariant) def __eq__(self, other): """ Drew added this. """ return graph_isomorphic(self, other) def __hash__(self): """ Drew added this. Note that it returns a value stored when "compute_invariant" is called. """ try: return self.hash except: self.compute_invariant() return self.hash def codim(self): codim = 0 for v in range(1, self.num_vertices() + 1): for expon, coef in self.M[v, 0].dict().items(): codim += expon[0] * coef for e in range(1, self.num_edges() + 1): for expon, coef in self.M[v, e].dict().items(): if expon[0] > 0: codim += coef for e in range(1, self.num_edges() + 1): if self.M[0, e] == 0: codim += 1 return codim def codim_undecorated(self): codim = 0 for e in range(1, self.num_edges() + 1): if self.M[0, e] == 0: codim += 1 return codim print("not implemented!!!!!!") return 1 def kappa_on_v(self, v): """ Drew added this. """ #print "kappa",self.M[v,0].dict() for ex, coef in self.M[v, 0].dict().items(): if ex[0] != 0: yield ex[0], coef def psi_no_loop_on_v(self, v): for edge in range(1, self.num_edges() + 1): if self.M[v, edge][0] == 1: psi_expon = self.M[v, edge][1] if psi_expon > 0: yield edge, psi_expon def psi_loop_on_v(self, v): for edge in range(1, self.num_edges() + 1): if self.M[v, edge][0] == 2: psi_expon1 = self.M[v, edge][1] psi_expon2 = self.M[v, edge][2] if psi_expon1 > 0: yield edge, psi_expon1, psi_expon2 def moduli_dim_v(self, v): """ Drew added this. """ return 3 * self.M[v, 0][0] - 3 + sum( (self.M[v, j][0] for j in range(1, self.num_edges() + 1))) def num_loops(self): count = 0 for edge in range(1, self.num_edges() + 1): for v in range(1, self.num_vertices() + 1): if self.M[v, edge][0] == 2: count += 1 break return count def num_undecorated_loops(self): count = 0 for edge in range(1, self.num_edges() + 1): for v in range(1, self.num_vertices() + 1): if self.M[v, edge] == 2: count += 1 break return count def num_full_edges(self): count = 0 for edge in range(1, self.num_edges() + 1): if sum((self.M[v, edge][0] for v in range(1, self.num_vertices() + 1))) == 2: count += 1 return count def forget_kappas(self): M = copy(self.M) for v in range(1, self.num_vertices() + 1): M[v, 0] = M[v, 0][0] return StrataGraph(M) def forget_decorations(self): M = Matrix(StrataGraph.R, [[self.M[r, c][0] for c in range(self.M.ncols())] for r in range(self.M.nrows())]) Gnew = StrataGraph(M) #Gnew.compute_invariant() return Gnew def is_loop(self, edge): for v in range(1, self.num_vertices() + 1): if self.M[v, edge][0] == 2: return True if self.M[v, edge][0] == 1: return False raise Exception("Unexpected!") ps_name = "ps" ps2_name = "ps_" def nice_matrix(self): Mnice = Matrix(SR, self.M.nrows(), self.M.ncols()) for edge in range(1, self.num_edges() + 1): Mnice[0, edge] = self.M[0, edge] for v in range(1, self.num_vertices() + 1): kappas = 1 for expon, coef in self.M[v, 0].dict().items(): if expon[0] == 0: Mnice[v, 0] += coef else: kappas *= var("ka{0}".format(expon[0]))**coef if kappas != 1: Mnice[v, 0] += kappas for edge in range(1, self.num_edges() + 1): psis = 1 for expon, coef in self.M[v, edge].dict().items(): if expon[0] == 0: Mnice[v, edge] += coef elif expon[0] == 1: psis *= var(StrataGraph.ps_name)**coef elif expon[0] == 2: psis *= var(StrataGraph.ps2_name)**coef if psis != 1: Mnice[v, edge] += psis return Mnice @staticmethod def from_nice_matrix(lists): Mx = Matrix(StrataGraph.R, len(lists), len(lists[0])) Mx[0, 0] = -1 Mx[0, :] = Matrix([lists[0]]) for v in range(1, len(lists)): if lists[v][0] in ZZ: Mx[v, 0] = lists[v][0] continue if lists[v][0].operator() == sage.symbolic.operators.add_vararg: operands = lists[v][0].operands() if len(operands) != 2: raise Exception("Input error!") genus = operands[1] #the genus kappas = operands[0] else: kappas = lists[v][0] genus = 0 if kappas.operator() == sage.symbolic.operators.mul_vararg: for operand in kappas.operands(): Mx[v, 0] += StrataGraph._kappaSR_monom_to_X(operand) Mx[v, 0] += genus else: Mx[v, 0] = StrataGraph._kappaSR_monom_to_X(kappas) + genus X = StrataGraph.Xvar for v in range(1, len(lists)): for edge in range(1, len(lists[0])): if lists[v][edge] in ZZ: Mx[v, edge] = lists[v][edge] else: for operand in lists[v][edge].operands(): if operand in ZZ: Mx[v, edge] += operand elif operand.operator() is None: #it is a ps or ps2 Mx[v, edge] += X elif operand.operator() == operator.pow: #it is ps^n or ps2^n Mx[v, edge] += X * operand.operands()[1] elif operand.operator( ) == sage.symbolic.operators.mul_vararg: #it is a ps^n*ps2^m op1, op2 = operand.operands() if op1.operator() is None: exp1 = 1 else: exp1 = op1.operand()[1] if op2.operator() == None: exp2 = 1 else: exp2 = op2.operand()[1] if exp1 >= exp2: Mx[v, edge] += exp1 * X + exp2 * X**2 else: Mx[v, edge] += exp1 * X**2 + exp2 * X return StrataGraph(Mx) @staticmethod def _kappaSR_monom_to_X(expr): X = StrataGraph.Xvar if expr in ZZ: return expr elif expr.operator() == None: ka_subscript = Integer(str(expr)[2:]) return X**ka_subscript elif expr.operator() == operator.pow: ops = expr.operands() expon = ops[1] ka = ops[0] ka_subscript = Integer(str(ka)[2:]) return expon * X**ka_subscript def nice_name(self): """ :return: """ if self.num_vertices() == 1: num_loops = self.num_loops() if num_loops > 1: return None elif num_loops == 1: if self.codim() == 1: return "D_irr" else: return None #else, there are no loops var_strs = [] for expon, coef in self.M[1, 0].dict().items(): if expon[0] == 0 or coef == 0: continue if coef == 1: var_strs.append("ka{0}".format(expon[0])) else: var_strs.append("ka{0}^{1}".format(expon[0], coef)) for he in range(1, self.num_edges() + 1): #should only be half edges now if self.M[1, he][1] > 1: var_strs.append("ps{0}^{1}".format(self.M[0, he], self.M[1, he][1])) elif self.M[1, he][1] == 1: var_strs.append("ps{0}".format(self.M[0, he])) if len(var_strs) > 0: return "*".join(var_strs) else: return "one" if self.num_vertices() == 2 and self.num_full_edges( ) == 1 and self.codim() == 1: #it is a boundary divisor v1_marks = [ self.M[0, j] for j in range(1, self.num_edges() + 1) if self.M[1, j] == 1 and self.M[0, j] != 0 ] v1_marks.sort() v2_marks = [ self.M[0, j] for j in range(1, self.num_edges() + 1) if self.M[2, j] == 1 and self.M[0, j] != 0 ] v2_marks.sort() if v1_marks < v2_marks: g = self.M[1, 0] elif v1_marks == v2_marks: if self.M[1, 0] <= self.M[2, 0]: g = self.M[1, 0] else: g = self.M[2, 0] else: g = self.M[2, 0] #temp = v1_marks v1_marks = v2_marks #v2_marks = temp if len(v1_marks) == 0: return "Dg{0}".format(g) else: return "Dg{0}m".format(g) + "_".join( [str(m) for m in v1_marks])
class StrataGraph(object): R = PolynomialRing(ZZ,"X",1,order='lex') Xvar = R.gen() def __init__(self,M=None,genus_list=None): #print genus_list if M: self.M = copy(M) elif genus_list: self.M = Matrix(StrataGraph.R,len(genus_list)+1,1,[-1]+genus_list) else: self.M = Matrix(StrataGraph.R,1,1,-1) def __repr__(self): """ Drew added this. """ name = self.nice_name() if name == None: return repr(self.nice_matrix()) else: return name def num_vertices(self): return self.M.nrows() - 1 def num_edges(self): return self.M.ncols() - 1 def h1(self): return self.M.ncols()-self.M.nrows()+1 def add_vertex(self,g): self.M = self.M.stack(Matrix(1,self.M.ncols())) self.M[-1,0] = g def add_edge(self,i1,i2,marking=0): self.M = self.M.augment(Matrix(self.M.nrows(),1)) self.M[0,-1] = marking if i1 > 0: self.M[i1,-1] += 1 if i2 > 0: self.M[i2,-1] += 1 def del_vertex(self,i): self.M = self.M[:i].stack(self.M[(i+1):]) def del_edge(self,i): self.M = self.M[0:,:i].augment(self.M[0:,(i+1):]) def compute_degree_vec(self): self.degree_vec = [sum(self.M[i,j][0] for j in range(1,self.M.ncols())) for i in range(1,self.M.nrows())] def degree(self,i): return self.degree_vec[i-1] def split_vertex(self,i,row1,row2): self.M = self.M.stack(Matrix(2,self.M.ncols(),row1+row2)) self.add_edge(self.M.nrows()-2, self.M.nrows()-1) self.del_vertex(i) def compute_parity_vec_original(self): X = StrataGraph.Xvar self.parity_vec = [(ZZ(1+self.M[i,0][0]+sum(self.M[i,k][1] for k in range(1,self.M.ncols()))+sum(self.M[i,k][2] for k in range(1,self.M.ncols()))+self.M[i,0].derivative(X).substitute(X=1)) % 2) for i in range(1,self.M.nrows())] def compute_parity_vec(self): X = StrataGraph.Xvar self.parity_vec = [(ZZ(1+self.M[i,0][0]+sum(self.M[i,k][1] for k in range(1,self.M.ncols()))+sum(self.M[i,k][2] for k in range(1,self.M.ncols()))+self.last_parity_summand(i)) % 2) for i in range(1,self.M.nrows())] def last_parity_summand(self,i): return sum(( expon[0] * coef for expon, coef in self.M[i,0].dict().items() )) def parity(self,i): return self.parity_vec[i-1] def replace_vertex_with_graph(self,i,G): X = StrataGraph.Xvar nv = self.num_vertices() ne = self.num_edges() #i should have degree d, there should be no classes near i, and G should have markings 1,...,d and genus equal to the genus of i hedge_list = [] for k in range(1,self.M.ncols()): for j in range(self.M[i,k]): hedge_list.append(k) self.del_vertex(i) for j in range(G.num_edges() - len(hedge_list)): self.add_edge(0,0) for j in range(G.num_vertices()): self.add_vertex(G.M[j+1,0]) col = ne+1 for k in range(1,G.M.ncols()): if G.M[0,k] > 0: mark = ZZ(G.M[0,k]) for j in range(G.num_vertices()): if self.M[nv+j,hedge_list[mark-1]] == 0: self.M[nv+j,hedge_list[mark-1]] = G.M[j+1,k] elif G.M[j+1,k] != 0: a = self.M[nv+j,hedge_list[mark-1]][1] b = G.M[j+1,k][1] self.M[nv+j,hedge_list[mark-1]] = 2 + max(a,b)*X + min(a,b)*X**2 else: for j in range(G.num_vertices()): self.M[nv+j,col] = G.M[j+1,k] col += 1 def compute_invariant(self): self.compute_parity_vec() self.compute_degree_vec() nr,nc = self.M.nrows(),self.M.ncols() self.invariant = [[self.M[i,0], [], [], [[] for j in range(1,nr)]] for i in range(1,nr)] for k in range(1,nc): L = [i for i in range(1,nr) if self.M[i,k] != 0] if len(L) == 1: if self.M[0,k] != 0: self.invariant[L[0]-1][2].append([self.M[0,k],self.M[L[0],k]]) else: self.invariant[L[0]-1][1].append(self.M[L[0],k]) else: self.invariant[L[0]-1][3][L[1]-1].append([self.M[L[0],k],self.M[L[1],k]]) self.invariant[L[1]-1][3][L[0]-1].append([self.M[L[1],k],self.M[L[0],k]]) for i in range(1,nr): self.invariant[i-1][3] = [term for term in self.invariant[i-1][3] if len(term) > 0] for term in self.invariant[i-1][3]: term.sort() self.invariant[i-1][3].sort() self.invariant[i-1][2].sort() self.invariant[i-1][1].sort() vertex_invariants = [[i,self.invariant[i-1]] for i in range(1,nr)] self.invariant.sort() vertex_invariants.sort(key=lambda x: x[1]) self.vertex_groupings = [] for i in range(nr-1): if i == 0 or vertex_invariants[i][1] != vertex_invariants[i-1][1]: self.vertex_groupings.append([]) self.vertex_groupings[-1].append(vertex_invariants[i][0]) #Drew added this self.invariant = tupleit(self.invariant) self.hash = hash(self.invariant) def __eq__(self,other): """ Drew added this. """ return graph_isomorphic(self, other) def __hash__(self): """ Drew added this. Note that it returns a value stored when "compute_invariant" is called. """ try: return self.hash except: self.compute_invariant() return self.hash def codim(self): codim = 0 for v in range(1, self.num_vertices()+1): for expon, coef in self.M[v,0].dict().items(): codim += expon[0]*coef for e in range(1, self.num_edges()+1): for expon, coef in self.M[v,e].dict().items(): if expon[0] > 0: codim += coef for e in range(1, self.num_edges()+1): if self.M[0,e] == 0: codim +=1 return codim def codim_undecorated(self): codim = 0 for e in range(1, self.num_edges()+1): if self.M[0,e] == 0: codim +=1 return codim print "not implemented!!!!!!" return 1 def kappa_on_v(self,v): """ Drew added this. """ #print "kappa",self.M[v,0].dict() for ex, coef in self.M[v,0].dict().items(): if ex[0] != 0: yield ex[0], coef def psi_no_loop_on_v(self,v): for edge in range(1,self.num_edges()+1): if self.M[v,edge][0] == 1: psi_expon = self.M[v,edge][1] if psi_expon > 0: yield edge, psi_expon def psi_loop_on_v(self,v): for edge in range(1,self.num_edges()+1): if self.M[v,edge][0] == 2: psi_expon1 = self.M[v,edge][1] psi_expon2 = self.M[v,edge][2] if psi_expon1 > 0: yield edge, psi_expon1, psi_expon2 def moduli_dim_v(self,v): """ Drew added this. """ return 3*self.M[v,0][0]-3 + sum(( self.M[v,j][0] for j in range(1, self.num_edges()+1 ) )) def num_loops(self): count = 0 for edge in range(1, self.num_edges()+1): for v in range(1, self.num_vertices()+1): if self.M[v,edge][0] == 2: count+=1 break return count def num_undecorated_loops(self): count = 0 for edge in range(1, self.num_edges()+1): for v in range(1, self.num_vertices()+1): if self.M[v,edge] == 2: count+=1 break return count def num_full_edges(self): count = 0 for edge in range(1, self.num_edges()+1): if sum(( self.M[v,edge][0] for v in range(1, self.num_vertices()+1 ))) == 2: count += 1 return count def forget_kappas(self): M = copy(self.M) for v in range(1, self.num_vertices()+1): M[v,0] = M[v,0][0] return StrataGraph(M) def forget_decorations(self): M = Matrix(StrataGraph.R,[[self.M[r,c][0] for c in range(self.M.ncols())] for r in range(self.M.nrows())] ) Gnew = StrataGraph(M) #Gnew.compute_invariant() return Gnew def is_loop(self,edge): for v in range(1, self.num_vertices()+1): if self.M[v,edge][0] == 2: return True if self.M[v,edge][0] == 1: return False raise Exception("Unexpected!") ps_name = "ps" ps2_name = "ps_" def nice_matrix(self): Mnice = Matrix(SR, self.M.nrows(), self.M.ncols()) for edge in range(1, self.num_edges()+1): Mnice[0,edge] = self.M[0,edge] for v in range(1, self.num_vertices()+1): kappas = 1 for expon, coef in self.M[v,0].dict().items(): if expon[0]==0: Mnice[v,0] += coef else: kappas *= var("ka{0}".format(expon[0]))**coef if kappas != 1: Mnice[v,0] += kappas for edge in range(1, self.num_edges()+1): psis = 1 for expon, coef in self.M[v,edge].dict().items(): if expon[0]==0: Mnice[v,edge] += coef elif expon[0]==1: psis *= var(StrataGraph.ps_name)**coef elif expon[0]==2: psis *= var(StrataGraph.ps2_name)**coef if psis != 1: Mnice[v,edge] += psis return Mnice @staticmethod def from_nice_matrix(lists): Mx = Matrix(StrataGraph.R, len(lists), len(lists[0])) Mx[0,0]=-1 Mx[0,:] = Matrix([lists[0]]) for v in range(1, len(lists)): if lists[v][0] in ZZ: Mx[v,0]=lists[v][0] continue if lists[v][0].operator() == sage.symbolic.operators.add_vararg: operands = lists[v][0].operands() if len(operands) != 2: raise Exception("Input error!") genus = operands[1] #the genus kappas = operands[0] else: kappas = lists[v][0] genus = 0 if kappas.operator() == sage.symbolic.operators.mul_vararg: for operand in kappas.operands(): Mx[v,0] += StrataGraph._kappaSR_monom_to_X(operand) Mx[v,0] += genus else: Mx[v,0] = StrataGraph._kappaSR_monom_to_X(kappas) + genus X = StrataGraph.Xvar for v in range(1, len(lists)): for edge in range(1, len(lists[0])): if lists[v][edge] in ZZ: Mx[v,edge] = lists[v][edge] else: for operand in lists[v][edge].operands(): if operand in ZZ: Mx[v,edge] += operand elif operand.operator() is None: #it is a ps or ps2 Mx[v,edge] += X elif operand.operator() == operator.pow: #it is ps^n or ps2^n Mx[v,edge] += X * operand.operands()[1] elif operand.operator() == sage.symbolic.operators.mul_vararg: #it is a ps^n*ps2^m op1,op2 = operand.operands() if op1.operator() is None: exp1 = 1 else: exp1 = op1.operand()[1] if op2.operator() == None: exp2 = 1 else: exp2 = op2.operand()[1] if exp1 >= exp2: Mx[v,edge] += exp1*X + exp2*X**2 else: Mx[v,edge] += exp1*X**2 + exp2*X return StrataGraph(Mx) @staticmethod def _kappaSR_monom_to_X(expr): X = StrataGraph.Xvar if expr in ZZ: return expr elif expr.operator() == None: ka_subscript = Integer(str(expr)[2:]) return X ** ka_subscript elif expr.operator() == operator.pow: ops = expr.operands() expon = ops[1] ka = ops[0] ka_subscript = Integer(str(ka)[2:]) return expon * X ** ka_subscript def nice_name(self): """ :return: """ if self.num_vertices() == 1: num_loops = self.num_loops() if num_loops >1: return None elif num_loops == 1: if self.codim() == 1: return "D_irr" else: return None #else, there are no loops var_strs = [] for expon, coef in self.M[1,0].dict().items(): if expon[0] == 0 or coef == 0: continue if coef == 1: var_strs.append("ka{0}".format(expon[0])) else: var_strs.append("ka{0}^{1}".format(expon[0],coef)) for he in range(1,self.num_edges()+1): #should only be half edges now if self.M[1,he][1] > 1: var_strs.append("ps{0}^{1}".format(self.M[0,he],self.M[1,he][1])) elif self.M[1,he][1] == 1: var_strs.append("ps{0}".format(self.M[0,he])) if len(var_strs) > 0: return "*".join(var_strs) else: return "one" if self.num_vertices() == 2 and self.num_full_edges() == 1 and self.codim() == 1: #it is a boundary divisor v1_marks = [self.M[0,j] for j in range(1, self.num_edges()+1) if self.M[1,j] == 1 and self.M[0,j] != 0] v1_marks.sort() v2_marks = [self.M[0,j] for j in range(1, self.num_edges()+1) if self.M[2,j] == 1 and self.M[0,j] != 0] v2_marks.sort() if v1_marks < v2_marks: g = self.M[1,0] elif v1_marks == v2_marks: if self.M[1,0] <= self.M[2,0]: g = self.M[1,0] else: g = self.M[2,0] else: g = self.M[2,0] #temp = v1_marks v1_marks = v2_marks #v2_marks = temp if len(v1_marks) == 0: return "Dg{0}".format(g) else: return "Dg{0}m".format(g) + "_".join([str(m) for m in v1_marks])