def plot(self, **kwds): """ EXAMPLES:: sage: X = gauge_theories.threeSU(3) sage: print X.plot().description() """ g = DiGraph(loops=True, sparse=True, multiedges=True) for G in self._gauge_groups: g.add_vertex(G) for field in self._fields: if isinstance(field, FieldBifundamental): g.add_edge(field.src, field.dst, field) if isinstance(field, FieldAdjoint): g.add_edge(field.node, field.node, field) return g.plot(vertex_labels=True, edge_labels=True, graph_border=True)
def to_dag(self): """ Returns a directed acyclic graph corresponding to the skew partition. EXAMPLES:: sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag() sage: dag.edges() [('0,1', '0,2', None), ('0,1', '1,1', None)] sage: dag.vertices() ['0,1', '0,2', '1,1', '2,0'] """ i = 0 #Make the skew tableau from the shape skew = [[1]*row_length for row_length in self.outer()] inner = self.inner() for i in range(len(inner)): for j in range(inner[i]): skew[i][j] = None G = DiGraph() for row in range(len(skew)): for column in range(len(skew[row])): if skew[row][column] is not None: string = "%d,%d" % (row, column) G.add_vertex(string) #Check to see if there is a node to the right if column != len(skew[row]) - 1: newstring = "%d,%d" % (row, column+1) G.add_edge(string, newstring) #Check to see if there is anything below if row != len(skew) - 1: if len(skew[row+1]) > column: if skew[row+1][column] is not None: newstring = "%d,%d" % (row+1, column) G.add_edge(string, newstring) return G
def _digraph(self): r""" Constructs the underlying digraph and stores the result as an attribute. EXAMPLES:: sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator sage: ops = [SwapIncreasingOperator(i) for i in range(2)] sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops) sage: Y._digraph Digraph on 6 vertices """ digraph = DiGraph() digraph.add_vertex(self._root) queue = [self._root] while queue: u = queue.pop() for (v, l) in self._successors(u): if v not in digraph: queue.append(v) digraph.add_edge(u, v, l) return digraph
def _digraph(self): r""" Constructs the underlying digraph and stores the result as an attribute. EXAMPLES:: sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator sage: ops = [SwapIncreasingOperator(i) for i in range(2)] sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops) sage: Y._digraph Digraph on 6 vertices """ digraph = DiGraph() digraph.add_vertex(self._root) queue = [self._root] while queue: u = queue.pop() for (v, l) in self._succesors(u): if v not in digraph: queue.append(v) digraph.add_edge(u, v, l) return digraph
class ParentBigOh(Parent,UniqueRepresentation): def __init__(self,ambiant): try: self._uniformizer = ambiant.uniformizer_name() except NotImplementedError: raise TypeError("Impossible to determine the name of the uniformizer") self._ambiant_space = ambiant self._models = DiGraph(loops=False) self._default_model = None Parent.__init__(self,ambiant.base_ring()) if self.base_ring() is None: self._base_precision = None else: if self.base_ring() == ambiant: self._base_precision = self else: self._base_precision = ParentBigOh(self.base_ring()) def __hash__(self): return id(self) def base_precision(self): return self._base_precision def precision(self): return self._precision def default_model(self): if self._default_mode is None: self.set_default_model() return self._default_model def set_default_model(self,model=None): if model is None: self._default_model = self._models.topological_sort()[-1] else: if self._models.has_vertex(model): self._default_model = model else: raise ValueError def add_model(self,model): from bigoh import BigOh if not isinstance(model,list): model = [model] for m in model: if not issubclass(m,BigOh): raise TypeError("A precision model must derive from BigOh but '%s' is not"%m) self._models.add_vertex(m) def delete_model(self,model): if isinstance(model,list): model = [model] for m in model: if self._models.has_vertex(m): self._models.delete_vertex(m) def update_model(self,old,new): from bigoh import BigOh if self._models.has_vertex(old): if not issubclass(new,BigOh): raise TypeError("A precision model must derive from BigOh but '%s' is not"%new) self._models.relabel({old:new}) else: raise ValueError("Model '%m' does not exist"%old) def add_modelconversion(self,domain,codomain,constructor=None,safemode=False): if not self._models.has_vertex(domain): if safemode: return raise ValueError("Model '%s' does not exist"%domain) if not self._models.has_vertex(codomain): if safemode: return raise ValueError("Model '%s' does not exist"%codomain) path = self._models.shortest_path(codomain,domain) if len(path) > 0: raise ValueError("Adding this conversion creates a cycle") self._models.add_edge(domain,codomain,constructor) def delete_modelconversion(self,domain,codomain): if not self._models.has_vertex(domain): raise ValueError("Model '%s' does not exist"%domain) if not self._models.has_vertex(codomain): raise ValueError("Model '%s' does not exist"%codomain) if not self._models_has_edge(domain,codomain): raise ValueError("No conversion from %s to %s"%(domain,codomain)) self._modelfs.delete_edge(domain,codomain) def uniformizer_name(self): return self._uniformizer def ambiant_space(self): return self._ambiant_space # ?!? def __call__(self,*args,**kwargs): return self._element_constructor_(*args,**kwargs) def _element_constructor_(self, *args, **kwargs): if kwargs.has_key('model'): del kwargs['model'] return kwargs['model'](self, *args, **kwargs) if len(args) > 0: from precision.bigoh import BigOh, ExactBigOh arg = args[0] if isinstance(arg,BigOh) and arg.is_exact(): return ExactBigOh(self) if self._models.has_vertex(arg.__class__) and arg.parent() is self: return arg if self._default_model is not None: try: return self._default_model(self,*args,**kwargs) except (AttributeError,ValueError,TypeError): pass models = self._models.topological_sort() models.reverse() for m in models: try: return m(self,*args,**kwargs) except (AttributeError,ValueError,TypeError,PrecisionError): pass raise PrecisionError("unable to create a BigOh object") def __repr__(self): return "Parent for BigOh in %s" % self._ambiant_space def models(self,graph=False): if graph: return self._models else: return self._models.vertices() def dimension(self): return self._ambiant_space.dimension() def indices_basis(self): return self._ambiant_space.indices_basis()
def reduced_rauzy_graph(self, n): r""" Returns the reduced Rauzy graph of order `n` of self. INPUT: - ``n`` - non negative integer. Every vertex of a reduced Rauzy graph of order `n` is a factor of length `n` of self. OUTPUT: Looped multi-digraph DEFINITION: For infinite periodic words (resp. for finite words of type `u^i u[0:j]`), the reduced Rauzy graph of order `n` (resp. for `n` smaller or equal to `(i-1)|u|+j`) is the directed graph whose unique vertex is the prefix `p` of length `n` of self and which has an only edge which is a loop on `p` labelled by `w[n+1:|w|] p` where `w` is the unique return word to `p`. In other cases, it is the directed graph defined as followed. Let `G_n` be the Rauzy graph of order `n` of self. The vertices are the vertices of `G_n` that are either special or not prolongable to the right or to the left. For each couple (`u`, `v`) of such vertices and each directed path in `G_n` from `u` to `v` that contains no other vertices that are special, there is an edge from `u` to `v` in the reduced Rauzy graph of order `n` whose label is the label of the path in `G_n`. .. NOTE:: In the case of infinite recurrent non periodic words, this definition correspond to the following one that can be found in [1] and [2] where a simple path is a path that begins with a special factor, ends with a special factor and contains no other vertices that are special: The reduced Rauzy graph of factors of length `n` is obtained from `G_n` by replacing each simple path `P=v_1 v_2 ... v_{\ell}` with an edge `v_1 v_{\ell}` whose label is the concatenation of the labels of the edges of `P`. EXAMPLES:: sage: w = Word(range(10)); w word: 0123456789 sage: g = w.reduced_rauzy_graph(3); g Looped multi-digraph on 2 vertices sage: g.vertices() [word: 012, word: 789] sage: g.edges() [(word: 012, word: 789, word: 3456789)] For the Fibonacci word:: sage: f = words.FibonacciWord()[:100] sage: g = f.reduced_rauzy_graph(8);g Looped multi-digraph on 2 vertices sage: g.vertices() [word: 01001010, word: 01010010] sage: g.edges() [(word: 01001010, word: 01010010, word: 010), (word: 01010010, word: 01001010, word: 01010), (word: 01010010, word: 01001010, word: 10)] For periodic words:: sage: from itertools import cycle sage: w = Word(cycle('abcd'))[:100] sage: g = w.reduced_rauzy_graph(3) sage: g.edges() [(word: abc, word: abc, word: dabc)] :: sage: w = Word('111') sage: for i in range(5) : w.reduced_rauzy_graph(i) Looped digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex Looped multi-digraph on 1 vertex Looped multi-digraph on 0 vertices For ultimately periodic words:: sage: sigma = WordMorphism('a->abcd,b->cd,c->cd,d->cd') sage: w = sigma.fixed_point('a')[:100]; w word: abcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd... sage: g = w.reduced_rauzy_graph(5) sage: g.vertices() [word: abcdc, word: cdcdc] sage: g.edges() [(word: abcdc, word: cdcdc, word: dc), (word: cdcdc, word: cdcdc, word: dc)] AUTHOR: Julien Leroy (March 2010): initial version REFERENCES: - [1] M. Bucci et al. A. De Luca, A. Glen, L. Q. Zamboni, A connection between palindromic and factor complexity using return words," Advances in Applied Mathematics 42 (2009) 60-74. - [2] L'ubomira Balkova, Edita Pelantova, and Wolfgang Steiner. Sequences with constant number of return words. Monatsh. Math, 155 (2008) 251-263. """ from sage.graphs.all import DiGraph from copy import copy g = copy(self.rauzy_graph(n)) # Otherwise it changes the rauzy_graph function. l = [v for v in g if g.in_degree(v)==1 and g.out_degree(v)==1] if g.num_verts() !=0 and len(l)==g.num_verts(): # In this case, the Rauzy graph is simply a cycle. g = DiGraph() g.allow_loops(True) g.add_vertex(self[:n]) g.add_edge(self[:n],self[:n],self[n:n+len(l)]) else: g.allow_loops(True) g.allow_multiple_edges(True) for v in l: [i] = g.neighbors_in(v) [o] = g.neighbors_out(v) g.add_edge(i,o,g.edge_label(i,v)[0]*g.edge_label(v,o)[0]) g.delete_vertex(v) return g
def rauzy_graph(self, n): r""" Returns the Rauzy graph of the factors of length n of self. The vertices are the factors of length `n` and there is an edge from `u` to `v` if `ua = bv` is a factor of length `n+1` for some letters `a` and `b`. INPUT: - ``n`` - integer EXAMPLES:: sage: w = Word(range(10)); w word: 0123456789 sage: g = w.rauzy_graph(3); g Looped digraph on 8 vertices sage: WordOptions(identifier='') sage: g.vertices() [012, 123, 234, 345, 456, 567, 678, 789] sage: g.edges() [(012, 123, 3), (123, 234, 4), (234, 345, 5), (345, 456, 6), (456, 567, 7), (567, 678, 8), (678, 789, 9)] sage: WordOptions(identifier='word: ') :: sage: f = words.FibonacciWord()[:100] sage: f.rauzy_graph(8) Looped digraph on 9 vertices :: sage: w = Word('1111111') sage: g = w.rauzy_graph(3) sage: g.edges() [(word: 111, word: 111, word: 1)] :: sage: w = Word('111') sage: for i in range(5) : w.rauzy_graph(i) Looped multi-digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 0 vertices Multi-edges are allowed for the empty word:: sage: W = Words('abcde') sage: w = W('abc') sage: w.rauzy_graph(0) Looped multi-digraph on 1 vertex sage: _.edges() [(word: , word: , word: a), (word: , word: , word: b), (word: , word: , word: c)] """ from sage.graphs.digraph import DiGraph multiedges = True if n == 0 else False g = DiGraph(loops=True, multiedges=multiedges) if n == self.length(): g.add_vertex(self) else: for w in self.factor_iterator(n+1): u = w[:-1] v = w[1:] a = w[-1:] g.add_edge(u,v,a) return g
def forcing_oriented_graph(self): r""" Return the forcing oriented graph for a 3-dimensional vector configuration. This is the directed graph on shards. The hyperplane arrangement with base region corresponding to the acyclic vector configuration is congruence normal if and only if the directed graph on shards is acyclic. OUTPUT: An oriented graph EXAMPLES:: sage: from cn_hyperarr.vector_classes import * sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,1,1]]) sage: fog = vc.forcing_oriented_graph(); fog Digraph on 11 vertices sage: fog.num_edges() 24 sage: tau = AA((1+sqrt(5))/2) sage: ncn = [[2*tau+1,2*tau,tau],[2*tau+2,2*tau+1,tau+1],[1,1,1],[tau+1,tau+1,tau],[2*tau,2*tau,tau],[tau+1,tau+1,1],[1,1,0],[0,1,0],[1,0,0],[tau+1,tau,tau]] sage: ncn_conf = VectorConfiguration(ncn); sage: ncn_fog = ncn_conf.forcing_oriented_graph(); ncn_fog Digraph on 29 vertices sage: ncn_fog.num_edges() 96 sage: ncn_fog.is_directed_acyclic() False TESTS: The ambient dimension should be 3:: sage: vc = VectorConfiguration([[1],[2],[3]]) sage: vc.forcing_oriented_graph() Traceback (most recent call last): ... AssertionError: The ambient dimension is not 3 """ nb_pts = self.n_vectors() shard_covectors = self.shard_covectors() hic = self.line_covectors() G = DiGraph() for shard_cov in shard_covectors: G.add_vertex(shard_cov) shard_index = shard_cov.index(0) potential_shards = (v for v in G.vertices() if v.index(0) != shard_index) for other_shard_cov in potential_shards: other_shard_index = other_shard_cov.index(0) # Get the potential ordering of forcing: forcing = True if other_shard_cov[shard_index] in [1, -1]: # shard_cov -> other_shard_cov first_cov, second_cov = shard_cov, other_shard_cov elif shard_cov[other_shard_index] in [1, -1]: # other_shard_cov -> shard_cov first_cov, second_cov = other_shard_cov, shard_cov else: forcing = False if forcing: # A forcing takes place hic1, hic2 = hic[Set([shard_index, other_shard_index])] sic1 = hic1 & shard_cov & other_shard_cov sic2 = hic2 & shard_cov & other_shard_cov if sic1 == hic1 or sic2 == hic2: G.add_edge(first_cov, second_cov) return G.copy(immutable=True)