def undirected_graph_has_odd_automorphism(g): n = len(g) edges = g.edges() G = Graph([list(range(n)), edges]) for sigma in G.automorphism_group().gens( ): # NOTE: it suffices to check generators edge_permutation = [ tuple(sorted([sigma(edge[0]), sigma(edge[1])])) for edge in edges ] index_permutation = [edges.index(e) for e in edge_permutation] if selection_sort(index_permutation) == -1: return True return False
def undirected_to_directed_graph_coefficient(undirected_graph, directed_graph): g = Graph(undirected_graph.edges()) h = Graph(directed_graph.edges()) are_isomorphic, sigma = g.is_isomorphic(h, certificate=True) assert are_isomorphic edges = directed_graph.edges() edge_permutation = [ edges.index((sigma[a], sigma[b])) if (sigma[a], sigma[b]) in edges else edges.index((sigma[b], sigma[a])) for (a, b) in undirected_graph.edges() ] sign = selection_sort(edge_permutation) multiplicity = len(g.automorphism_group()) // len( DiGraph(directed_graph.edges()).automorphism_group()) return sign * multiplicity
def automorphism_group(self): r""" The automorphism group of the graph. EXAMPLES: :: sage: from boolean_cayley_graphs.royle_x_graph import royle_x_graph sage: g = royle_x_graph() sage: from boolean_cayley_graphs.strongly_regular_graph import StronglyRegularGraph sage: srg = StronglyRegularGraph(g) sage: srg.automorphism_group Permutation Group with generators [(11,21)(12,22)(13,23)(14,24)(15,25)(16,26)(17,27)(18,28)(19,29)(20,30)(36,37)(44,49)(45,50)(46,51)(47,52)(48,53), (5,11)(6,12)(7,13)(8,14)(9,15)(10,16)(27,31)(28,32)(29,33)(30,34)(37,38)(43,44)(50,54)(51,55)(52,56)(53,57), (3,4)(6,7)(8,9)(12,13)(14,15)(17,18)(22,23)(24,25)(27,28)(31,32)(41,42)(47,48)(52,53)(56,57)(59,60)(61,62), (2,3)(5,6)(9,10)(11,12)(15,16)(18,19)(21,22)(25,26)(28,29)(32,33)(40,41)(46,47)(51,52)(55,56)(58,59)(62,63), (2,5)(3,6)(4,7)(14,17)(15,18)(16,19)(24,27)(25,28)(26,29)(34,35)(38,39)(44,45)(49,50)(55,58)(56,59)(57,60), (1,2)(6,8)(7,9)(12,14)(13,15)(19,20)(22,24)(23,25)(29,30)(33,34)(39,40)(45,46)(50,51)(54,55)(59,61)(60,62), (1,20)(2,19)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11)(37,43)(38,44)(39,45)(40,46)(41,47)(42,48), (0,1)(2,38,4,36)(3,37)(5,57,23,46)(6,53,22,51)(7,48,21,55)(8,17,26,33)(9,27,25,29)(10,31,24,19)(11,56,13,47)(12,52)(14,18,16,32)(15,28)(20,58,34,60)(30,59)(35,39)(40,43,42,49)(41,44)(45,63,54,61)(50,62)] """ return Graph.automorphism_group(self)
def restricted_automorphism_group(self, vertex_labels=None): r""" Return the restricted automorphism group. First, let the linear automorphism group be the subgroup of the Euclidean group `E(d) = GL(d,\RR) \ltimes \RR^d` preserving the `d`-dimensional polyhedron. The Euclidean group acts in the usual way `\vec{x}\mapsto A\vec{x}+b` on the ambient space. The restricted automorphism group is the subgroup of the linear automorphism group generated by permutations of vertices. If the polytope is full-dimensional, it is equal to the full (unrestricted) automorphism group. INPUT: - ``vertex_labels`` -- a tuple or ``None`` (default). The labels of the vertices that will be used in the output permutation group. By default, the vertices are used themselves. OUTPUT: A :class:`PermutationGroup<sage.groups.perm_gps.permgroup.PermutationGroup_generic>` acting on the vertices (or the ``vertex_labels``, if specified). REFERENCES: [BSS2009]_ EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) sage: Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) Permutation Group with generators [(2,3), (1,2)(3,4), (1,4)] sage: G = Z3square.restricted_automorphism_group(); G Permutation Group with generators [((1,2),(2,1)), ((0,0),(1,2))((2,1),(3,3)), ((0,0),(3,3))] sage: tuple(G.domain()) == Z3square.vertices() True sage: G.orbit(Z3square.vertices()[0]) ((0, 0), (1, 2), (3, 3), (2, 1)) sage: cell24 = LatticePolytope_PPL( ....: (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1), ....: (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1), ....: (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0), ....: (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)) sage: cell24.restricted_automorphism_group().cardinality() 1152 """ if not self.is_full_dimensional(): return self.affine_lattice_polytope().\ restricted_automorphism_group(vertex_labels=vertex_labels) if vertex_labels is None: vertex_labels = self.vertices() from sage.groups.perm_gps.permgroup import PermutationGroup from sage.graphs.graph import Graph # good coordinates for the vertices v_list = [] for v in self.minimized_generators(): assert v.divisor().is_one() v_coords = (1,) + v.coefficients() v_list.append(vector(v_coords)) # Finally, construct the graph Qinv = sum( v.column() * v.row() for v in v_list ).inverse() G = Graph() for i in range(0,len(v_list)): for j in range(i+1,len(v_list)): v_i = v_list[i] v_j = v_list[j] G.add_edge(vertex_labels[i], vertex_labels[j], v_i * Qinv * v_j) return G.automorphism_group(edge_labels=True)
def restricted_automorphism_group(self, vertex_labels=None): r""" Return the restricted automorphism group. First, let the linear automorphism group be the subgroup of the Euclidean group `E(d) = GL(d,\RR) \ltimes \RR^d` preserving the `d`-dimensional polyhedron. The Euclidean group acts in the usual way `\vec{x}\mapsto A\vec{x}+b` on the ambient space. The restricted automorphism group is the subgroup of the linear automorphism group generated by permutations of vertices. If the polytope is full-dimensional, it is equal to the full (unrestricted) automorphism group. INPUT: - ``vertex_labels`` -- a tuple or ``None`` (default). The labels of the vertices that will be used in the output permutation group. By default, the vertices are used themselves. OUTPUT: A :class:`PermutationGroup<sage.groups.perm_gps.permgroup.PermutationGroup_generic>` acting on the vertices (or the ``vertex_labels``, if specified). REFERENCES: [BSS2009]_ EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) sage: Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) == PermutationGroup([[(2,3)],[(1,2),(3,4)]]) True sage: G = Z3square.restricted_automorphism_group() sage: G == PermutationGroup([[((1,2),(2,1))],[((0,0),(1,2)),((2,1),(3,3))],[((0,0),(3,3))]]) True sage: set(G.domain()) == set(Z3square.vertices()) True sage: set(map(tuple,G.orbit(Z3square.vertices()[0]))) == set([(0, 0), (1, 2), (3, 3), (2, 1)]) True sage: cell24 = LatticePolytope_PPL( ....: (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1), ....: (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1), ....: (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0), ....: (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)) sage: cell24.restricted_automorphism_group().cardinality() 1152 """ if not self.is_full_dimensional(): return self.affine_lattice_polytope().\ restricted_automorphism_group(vertex_labels=vertex_labels) if vertex_labels is None: vertex_labels = self.vertices() from sage.graphs.graph import Graph # good coordinates for the vertices v_list = [] for v in self.minimized_generators(): assert v.divisor() == 1 v_coords = (1,) + tuple(Integer(mpz) for mpz in v.coefficients()) v_list.append(vector(v_coords)) # Finally, construct the graph Qinv = sum( v.column() * v.row() for v in v_list ).inverse() G = Graph() for i in range(len(v_list)): for j in range(i+1,len(v_list)): v_i = v_list[i] v_j = v_list[j] G.add_edge(vertex_labels[i], vertex_labels[j], v_i * Qinv * v_j) return G.automorphism_group(edge_labels=True)